GitFOSS
William Nemenchaimprove app
5c6496d (parent 48b426e)4/10/2024, 1:10:30 AM
improve app
+ 385
- 301
@@ -1,5 +1,5 @@
 {
-  "_generatedAtUnix": 1712538021580,
+  "_generatedAtUnix": 1712711081241,
   "_hashAlgorithm": "sha1",
   "_version": 2,
   "assets": {

...
@@ -16,7 +16,7 @@
   },
   "islands": {
     "AppRouter": {
-      "hash": "e5a99796c0971b1a27a880f28601e8aab4b33f34",
+      "hash": "503ea3936602d644f38a7d20fa990d7d050b0d12",
       "pathSource": "./app/islands/AppRouter.tsx",
       "pathBundle": "./public/.islands/AppRouter.bundle.js",
       "pathSourceMap": "./public/.islands/AppRouter.bundle.js.map"

...
@@ -52,7 +52,7 @@
       "pathSourceMap": "./public/.islands/RepositoryCommitSummaryLine.bundle.js.map"
     },
     "RepositoryCreateForm": {
-      "hash": "d4a64ab2f718fa6b77ea561d33adb242a831e107",
+      "hash": "1188f10449f61ba13d960e4656eff51771688b0b",
       "pathSource": "./app/islands/RepositoryCreateForm.tsx",
       "pathBundle": "./public/.islands/RepositoryCreateForm.bundle.js",
       "pathSourceMap": "./public/.islands/RepositoryCreateForm.bundle.js.map"

...
@@ -64,13 +64,13 @@
       "pathSourceMap": "./public/.islands/RepositoryFilesDiffsList.bundle.js.map"
     },
     "RepositoryForkForm": {
-      "hash": "95d83a51500d8a10819df92c81e16e4891640a9b",
+      "hash": "5213fa59ac3971ce10dea7bbf3ed6771761fb4e7",
       "pathSource": "./app/islands/RepositoryForkForm.tsx",
       "pathBundle": "./public/.islands/RepositoryForkForm.bundle.js",
       "pathSourceMap": "./public/.islands/RepositoryForkForm.bundle.js.map"
     },
     "RepositoryHero": {
-      "hash": "1539f74a6345fe47637d62faea2e5cc7504c6a72",
+      "hash": "9856ab7b1b73d82476e8cfae0adab2af53e62c1b",
       "pathSource": "./app/islands/RepositoryHero.tsx",
       "pathBundle": "./public/.islands/RepositoryHero.bundle.js",
       "pathSourceMap": "./public/.islands/RepositoryHero.bundle.js.map"

...
@@ -110,11 +110,11 @@
       "pathSource": "./app/views/InternalErrorView.tsx"
     },
     "LoginView": {
-      "hash": "367f96c1512dd718dcd3380abe84ea44fab1960f",
+      "hash": "f6ac28e71caa03457bd6a50564d8a08abbd4e8a3",
       "pathSource": "./app/views/auth/LoginView.tsx"
     },
     "RegisterView": {
-      "hash": "482ee764c0886fcca1cd7ec010d66e8244f71e9a",
+      "hash": "7db4267b67a6d6eed0dd256399e02b4ff9d1d7e2",
       "pathSource": "./app/views/auth/RegisterView.tsx"
     },
     "OrganizationDetailsView": {

...
@@ -134,7 +134,7 @@
       "pathSource": "./app/views/repository/RepositoryCompareView.tsx"
     },
     "RepositoryCreateView": {
-      "hash": "ee8113a9576aa434e4f31dd8cddf559872b8087d",
+      "hash": "b7138339dcb62e965acd1a1deb9ecc75412b333b",
       "pathSource": "./app/views/repository/RepositoryCreateView.tsx"
     },
     "RepositoryDetailsView": {

...
@@ -146,11 +146,11 @@
       "pathSource": "./app/views/repository/RepositoryExploreView.tsx"
     },
     "RepositoryForkView": {
-      "hash": "63f15218c58170202e5ca5ba21adb1df9b9811fd",
+      "hash": "2b09c90107b865e627c524ed9983efcb457b7fe1",
       "pathSource": "./app/views/repository/RepositoryForkView.tsx"
     },
     "RepositoryShowObjectView": {
-      "hash": "4e3a98afeeea8ac3d8333c8fa114ef6846482c2c",
+      "hash": "eaccea13f91094a106ba6815ca6d8d5765de0c29",
       "pathSource": "./app/views/repository/RepositoryShowObjectView.tsx"
     },
     "RepositoryPullRequestCreateView": {

...
@@ -165,12 +165,28 @@
       "hash": "33831a5912cdf2e8dd0f44f6159ef6b438322445",
       "pathSource": "./app/views/repositoryPullRequests/RepositoryPullRequestsView.tsx"
     },
+    "SettingsKeyAddView": {
+      "hash": "584c3cd4b6821f96a4129dfeaac8b54bf9cbcff6",
+      "pathSource": "./app/views/settings/SettingsKeyAddView.tsx"
+    },
+    "SettingsKeyUpdateView": {
+      "hash": "18b98cb52792e2ad59b99d1995e5c15e81b67c95",
+      "pathSource": "./app/views/settings/SettingsKeyUpdateView.tsx"
+    },
+    "SettingsKeysListView": {
+      "hash": "deebae0aaf402482f8ff1298921d9f6cd5016619",
+      "pathSource": "./app/views/settings/SettingsKeysListView.tsx"
+    },
+    "SettingsView": {
+      "hash": "83a043d69f6544f5f605779f77f251f4ee7810cf",
+      "pathSource": "./app/views/settings/SettingsView.tsx"
+    },
     "UserDashboardView": {
       "hash": "272155a4521b51a4849c4a1bb4b7a2db717a369f",
       "pathSource": "./app/views/user/UserDashboardView.tsx"
     },
     "UserDetailsView": {
-      "hash": "042857aba2aef94f81ce321b479bbb8109a78c6b",
+      "hash": "ade40bdda227fd333fb3c4f05e9d83a9e7d12747",
       "pathSource": "./app/views/user/UserDetailsView.tsx"
     }
   }

app/components/PageHeader.tsx
@@ -33,12 +33,6 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
           >
             {commonProps.currentUserUsername || "ghost"}
           </a>
-          <a
-            aria-label={"Log off your account"}
-            href={buildRouteLink(AppRoute.AUTH_LOGOUT_ACTION, null)}
-          >
-            Logout
-          </a>
         </>
       );
     }

...
@@ -87,17 +81,12 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
             </a>
           )}
           <a
-            aria-label={`Switch to ${
-              themeScheme === "light" ? "dark" : "light"
-            } theme`}
+            aria-label={`Switch to ${invertThemeScheme} theme`}
             data-smooth-scroll={"disabled"}
             href={buildRouteLink(AppRoute.THEME_SET_SCHEME_ACTION, {
               themeScheme: invertThemeScheme,
             })}
-            style={{ color: NamedColors.TEXT_MUTED[themeScheme] }}
-            title={`Click to enable ${
-              themeScheme === "light" ? "dark" : "light"
-            } mode`}
+            title={`Click to enable ${invertThemeScheme} mode`}
           >
             {`${themeScheme === "light" ? "Dark" : "Light"} mode`}
           </a>

@@ -13,7 +13,7 @@ type Const = {
 };
 
 export const Const: Const = {
-  APP_NAME: "GitFOSS",
+  APP_NAME: "GitBase",
   PRIMARY_BRANCH_REF: "master",
   DEFAULT_HEAD_REF: "HEAD",
   DEFAULT_THEME_SCHEME: "light",

app/islands/RepositoryCreateForm.tsx
@@ -5,11 +5,14 @@ import React, { useCallback, useEffect, useState } from "react";
 // generated via script[generate:prisma]
 import type { Organization } from "@prisma/client";
 // app
+import type { WithThemeSchemeProp } from "../types";
+import { slugify } from "../utils/shared";
 import { Button } from "../components/Button.styled";
+import { Card } from "../components/Card.styled";
 import { Grid } from "../components/Grid";
-import { slugify } from "../utils/shared";
+import { Select, TextArea, TextInput } from "../components";
 
-export interface RepositoryCreateFormProps {
+export interface RepositoryCreateFormProps extends WithThemeSchemeProp {
   availableParentOrgs: Organization[];
   editMode?: boolean;
   initialValues?: {

...
@@ -25,6 +28,7 @@ export interface RepositoryCreateFormProps {
 const SHORT_DESCRIPTION_MAX_LENGTH = 140;
 
 const RepositoryCreateForm: ReactIsland<RepositoryCreateFormProps> = ({
+  themeScheme,
   availableParentOrgs,
   editMode = false,
   initialValues = undefined,

...
@@ -118,7 +122,7 @@ const RepositoryCreateForm: ReactIsland<RepositoryCreateFormProps> = ({
     if (
       slugInputDirty === false &&
       displayName != null &&
-      displayName.trim() !== "" &&
+      // displayName.trim() !== "" &&
       nextSlug !== slug
     ) {
       setSlug(nextSlug);

...
@@ -126,184 +130,213 @@ const RepositoryCreateForm: ReactIsland<RepositoryCreateFormProps> = ({
   }, [displayName, slug, slugInputDirty, setSlug]);
 
   return (
-    <div>
-      <fieldset>
-        <legend>Repository details</legend>
-        {/* Repository Name */}
-        <Grid.Col fluid nowrap>
-          <label htmlFor={"repo_display_name"}>
-            Repository Name <span>(*)</span>:
-          </label>
-          <input
-            name={"repo_display_name"}
-            onChange={onDisplayNameInputChange}
-            placeholder={"i.e. My Super Project"}
-            required
-            style={styles.inputMaxWidth}
-            type={"text"}
-            value={displayName}
-          />
-        </Grid.Col>
-        <Grid.Row fluid nowrap alignItems={"center"}>
-          {/* Parent Organization Select */}
-          <Grid.Col fluid nowrap>
+    <Grid.Col fluid nowrap gap={24}>
+      <Grid.Col fluid nowrap gap={8}>
+        <label>
+          <strong>Repository details</strong>
+        </label>
+        <Card themeScheme={themeScheme} style={{ gap: 16 }}>
+          {/* Repository Name */}
+          <Grid.Col fluid nowrap gap={4}>
             <label htmlFor={"repo_display_name"}>
-              Owner Organization <span>(*)</span>:
+              Repository Name<span style={{ color: "red" }}>*</span>:
             </label>
-            <select
-              defaultValue={
-                availableParentOrgs.length >= 1
-                  ? availableParentOrgs[0].slug
-                  : initialValues?.parent_org_slug
-              }
-              name={"parent_org_slug"}
+            <TextInput
+              themeScheme={themeScheme}
+              name={"repo_display_name"}
+              onChange={onDisplayNameInputChange}
+              placeholder={"i.e. My Super Project"}
               required
               style={styles.inputMaxWidth}
-            >
-              {availableParentOrgs.map((org) => (
-                <option key={org.id} value={org.slug}>
-                  {org.displayName || org.slug}
-                </option>
-              ))}
-            </select>
+              type={"text"}
+              value={displayName}
+            />
           </Grid.Col>
-          {/* Repository Slug */}
-          <Grid.Col fluid nowrap>
-            <label htmlFor={"repo_slug"}>
-              Repository Slug <span>(*)</span>:
+          <Grid.Row fluid nowrap gap={16} alignItems={"center"}>
+            {/* Parent Organization Select */}
+            <Grid.Col fluid nowrap gap={4}>
+              <label htmlFor={"repo_display_name"}>
+                Owner Organization<span style={{ color: "red" }}>*</span>:
+              </label>
+              <Select
+                required
+                themeScheme={themeScheme}
+                name={"parent_org_slug"}
+                defaultValue={
+                  availableParentOrgs.length >= 1
+                    ? availableParentOrgs[0].slug
+                    : initialValues?.parent_org_slug
+                }
+                style={styles.inputMaxWidth}
+              >
+                {availableParentOrgs.map((org) => (
+                  <option key={org.id} value={org.slug}>
+                    {org.displayName || org.slug}
+                  </option>
+                ))}
+              </Select>
+            </Grid.Col>
+            {/* Repository Slug */}
+            <Grid.Col fluid nowrap gap={4}>
+              <label htmlFor={"repo_slug"}>
+                Repository Slug<span style={{ color: "red" }}>*</span>:
+              </label>
+              <TextInput
+                themeScheme={themeScheme}
+                name={"repo_slug"}
+                onChange={onSlugInputChange}
+                placeholder={"i.e. my-super-project"}
+                required
+                style={styles.inputMaxWidth}
+                type={"text"}
+                value={slug}
+              />
+            </Grid.Col>
+          </Grid.Row>
+          {/* Repository Visibility */}
+          <Grid.Col fluid nowrap gap={4}>
+            <label htmlFor={"repo_visibility"}>
+              Repository Visibility<span style={{ color: "red" }}>*</span>:
             </label>
-            <input
-              name={"repo_slug"}
-              onChange={onSlugInputChange}
-              placeholder={"i.e. my-super-project"}
-              required
+            <Select
+              themeScheme={themeScheme}
+              name={"repo_visibility"}
+              defaultValue={"PRIVATE"}
+              style={styles.inputMaxWidth}
+            >
+              <option key={"private"} value={"PRIVATE"}>
+                Private
+              </option>
+              <option key={"unlisted"} value={"UNLISTED"}>
+                Unlisted
+              </option>
+              <option key={"public"} value={"PUBLIC"}>
+                Public
+              </option>
+            </Select>
+          </Grid.Col>
+        </Card>
+      </Grid.Col>
+      <Grid.Col fluid nowrap gap={8}>
+        <label>
+          <strong>Repository description</strong>
+        </label>
+        <Card themeScheme={themeScheme} style={{ gap: 16 }}>
+          {/* Short Description */}
+          <Grid.Col fluid nowrap gap={4}>
+            <label htmlFor={"repo_short_description"}>Short Description:</label>
+            <TextArea
+              themeScheme={themeScheme}
+              name={"repo_short_description"}
+              maxLength={SHORT_DESCRIPTION_MAX_LENGTH}
+              onChange={onShortDescriptionTextAreaChange}
+              placeholder={"i.e. A super project about things that are super!"}
+              style={shortDescriptionStyles}
+              value={shortDescription}
+            ></TextArea>
+            <span style={styles.alignSelfEnd}>
+              {shortDescription.length}/{SHORT_DESCRIPTION_MAX_LENGTH}
+            </span>
+          </Grid.Col>
+          {/* Website URL */}
+          <Grid.Col fluid nowrap gap={4}>
+            <label htmlFor={"repo_website_url"}>Website URL:</label>
+            <TextInput
+              themeScheme={themeScheme}
+              name={"repo_website_url"}
+              defaultValue={initialValues?.repo_website_url}
+              placeholder={"i.e. https://www.super-project.com"}
               style={styles.inputMaxWidth}
               type={"text"}
-              value={slug}
             />
           </Grid.Col>
-        </Grid.Row>
-        {/* Repository Visibility */}
-        <Grid.Col fluid nowrap>
-          <label htmlFor={"repo_visibility"}>
-            Repository Visibility <span>(*)</span>:
-          </label>
-          <select
-            defaultValue={"PRIVATE"}
-            name={"repo_visibility"}
-            style={styles.inputMaxWidth}
-          >
-            <option key={"private"} value={"PRIVATE"}>
-              Private
-            </option>
-            <option key={"unlisted"} value={"UNLISTED"}>
-              Unlisted
-            </option>
-            <option key={"public"} value={"PUBLIC"}>
-              Public
-            </option>
-          </select>
-        </Grid.Col>
-      </fieldset>
-      <fieldset>
-        <legend>Repository description</legend>
-        {/* Short Description */}
-        <Grid.Col fluid nowrap>
-          <label htmlFor={"repo_short_description"}>Short Description:</label>
-          <textarea
-            maxLength={SHORT_DESCRIPTION_MAX_LENGTH}
-            name={"repo_short_description"}
-            onChange={onShortDescriptionTextAreaChange}
-            placeholder={"i.e. A super project about things that are super!"}
-            style={shortDescriptionStyles}
-            value={shortDescription}
-          ></textarea>
-          <span style={styles.alignSelfEnd}>
-            {shortDescription.length}/{SHORT_DESCRIPTION_MAX_LENGTH}
-          </span>
-        </Grid.Col>
-        {/* Website URL */}
-        <Grid.Col fluid nowrap>
-          <label htmlFor={"repo_website_url"}>Website URL:</label>
-          <input
-            defaultValue={initialValues?.repo_website_url}
-            name={"repo_website_url"}
-            placeholder={"i.e. https://www.super-project.com"}
-            style={styles.inputMaxWidth}
-            type={"text"}
-          />
-        </Grid.Col>
-        {/* Keywords */}
-        <Grid.Col fluid nowrap>
-          <label htmlFor={"repo_keywords_add"}>Keywords:</label>
-          <input type={"hidden"} name={"repo_keywords"} value={keywords} />
-          <input
-            name={"repo_keywords_add"}
-            onChange={onKeywordsInputChange}
-            placeholder={"Keywords separated by a coma (,)..."}
-            style={styles.inputMaxWidth}
-            type={"text"}
-          />
-          {keywords.map((word, idx) => (
-            <input
-              disabled
-              key={[idx, word].join(":")}
+          {/* Keywords */}
+          <Grid.Col fluid nowrap gap={4}>
+            <label htmlFor={"repo_keywords_add"}>Keywords:</label>
+            <input type={"hidden"} name={"repo_keywords"} value={keywords} />
+            <TextInput
+              themeScheme={themeScheme}
+              name={"repo_keywords_add"}
+              onChange={onKeywordsInputChange}
+              placeholder={"Keywords separated by a coma (,)..."}
               style={styles.inputMaxWidth}
               type={"text"}
-              value={word}
             />
-          ))}
-        </Grid.Col>
-      </fieldset>
-      <fieldset>
-        <legend>Repository setup</legend>
-        {/* Initialise Read Me file? */}
-        <Grid.Row fluid nowrap>
-          <label htmlFor={"repo_init_readme_file"} style={styles.labelFlexOne}>
-            Initialize with empty README.md file?
-          </label>
-          <input
-            defaultChecked={false}
-            name={"repo_init_readme_file"}
-            type={"checkbox"}
-          />
-        </Grid.Row>
-        <Grid.Row fluid nowrap>
+            {keywords.map((word, idx) => (
+              <TextInput
+                themeScheme={themeScheme}
+                disabled
+                key={[idx, word].join(":")}
+                style={styles.inputMaxWidth}
+                type={"text"}
+                value={word}
+              />
+            ))}
+          </Grid.Col>
+        </Card>
+      </Grid.Col>
+      <Grid.Col fluid nowrap gap={8}>
+        <label>
+          <strong>Repository setup</strong>
+        </label>
+        <Card themeScheme={themeScheme} style={{ gap: 16 }}>
+          {/* Initialise Read Me file? */}
+          <Grid.Row fluid nowrap gap={16}>
+            <label
+              htmlFor={"repo_init_readme_file"}
+              style={styles.labelFlexOne}
+            >
+              Initialize with empty README.md file?
+            </label>
+            <input
+              defaultChecked={false}
+              name={"repo_init_readme_file"}
+              type={"checkbox"}
+            />
+          </Grid.Row>
           {/* Initialise License file? */}
-          <label htmlFor={"repo_init_readme_file"} style={styles.labelFlexOne}>
-            Initialize with a LICENSE file?
-          </label>
-          <select
-            defaultValue={"MIT"}
-            disabled={repoInitLicenseFileChecked === false}
-            name={"repo_init_license_kind"}
-          >
-            <option key={"license:mit"} value={"mit"}>
-              MIT License
-            </option>
-            <option key={"license:gnu-gpl-v3"} value={"gnu-gpl-v3"}>
-              GNU GPL v.3.0
-            </option>
-            <option key={"license:gnu-agpl-v3"} value={"gnu-agpl-v3"}>
-              AGPL v.3.0
-            </option>
-            <option key={"license:gnu-lgpl-v3"} value={"gnu-lgpl-v3"}>
-              LGPL v.3.0
-            </option>
-          </select>
-          <input
-            checked={repoInitLicenseFileChecked}
-            name={"repo_init_license_file"}
-            onChange={onRepoInitLicenseFileInputChange}
-            type={"checkbox"}
-          />
-        </Grid.Row>
-      </fieldset>
+          <Grid.Row fluid nowrap gap={16} alignItems={"center"}>
+            <label
+              htmlFor={"repo_init_readme_file"}
+              style={styles.labelFlexOne}
+            >
+              Initialize with a LICENSE file?
+            </label>
+            <Select
+              themeScheme={themeScheme}
+              name={"repo_init_license_kind"}
+              defaultValue={"MIT"}
+              disabled={repoInitLicenseFileChecked === false}
+              style={{ width: "auto" }}
+            >
+              <option key={"license:mit"} value={"mit"}>
+                MIT License
+              </option>
+              <option key={"license:gnu-gpl-v3"} value={"gnu-gpl-v3"}>
+                GNU GPL v.3.0
+              </option>
+              <option key={"license:gnu-agpl-v3"} value={"gnu-agpl-v3"}>
+                AGPL v.3.0
+              </option>
+              <option key={"license:gnu-lgpl-v3"} value={"gnu-lgpl-v3"}>
+                LGPL v.3.0
+              </option>
+            </Select>
+            <input
+              checked={repoInitLicenseFileChecked}
+              name={"repo_init_license_file"}
+              onChange={onRepoInitLicenseFileInputChange}
+              type={"checkbox"}
+            />
+          </Grid.Row>
+        </Card>
+      </Grid.Col>
+
       {/* Submit Button */}
       <Button style={styles.inputMaxWidth} type={"submit"}>
         Create Repository
       </Button>
-    </div>
+    </Grid.Col>
   );
 };
 

...
@@ -318,7 +351,7 @@ const styles = {
   },
   labelFlexOne: {
     flex: 1,
-    marginRight: 8,
+    marginRight: 16,
   },
   shortDescriptionTextArea: {
     minHeight: 75,

app/islands/RepositoryForkForm.tsx
@@ -7,7 +7,7 @@ import type { Organization, ResourceVisibility } from "@prisma/client";
 // app
 import type { WithThemeSchemeProp } from "../types";
 import { slugify } from "../utils/shared";
-import { Button, Grid, Select, TextInput } from "../components";
+import { Button, Card, Grid, Select, TextInput } from "../components";
 
 export interface RepositoryForkFormProps {
   disabled?: boolean;

...
@@ -82,104 +82,107 @@ const RepositoryForkForm: ReactIsland<
   }, [displayName, slug, slugInputDirty, setSlug]);
 
   return (
-    <div>
-      <fieldset>
-        <legend>Fork details</legend>
-        <Grid.Col fluid nowrap gap={8}>
-          {/* Repository Name */}
-          <Grid.Col fluid nowrap gap={4}>
-            <label htmlFor={"target_repo_display_name"}>
-              Repository Name <span>(*)</span>:
-            </label>
-            <TextInput
-              themeScheme={themeScheme}
-              name={"target_repo_display_name"}
-              disabled={disabled}
-              onChange={onDisplayNameInputChange}
-              placeholder={"i.e. My Super Project"}
-              required
-              style={styles.inputMaxWidth}
-              type={"text"}
-              value={displayName}
-            />
-          </Grid.Col>
-          <Grid.Row fluid nowrap alignItems={"center"} gap={8}>
-            {/* Parent Organization Select */}
+    <Grid.Col fluid nowrap gap={24}>
+      <Grid.Col fluid nowrap gap={8}>
+        <label>
+          <strong>Fork details</strong>
+        </label>
+        <Card themeScheme={themeScheme}>
+          <Grid.Col fluid nowrap gap={16}>
+            {/* Repository Name */}
             <Grid.Col fluid nowrap gap={4}>
-              <label htmlFor={"target_org_slug"}>
-                Owner Organization <span>(*)</span>:
+              <label htmlFor={"target_repo_display_name"}>
+                Repository Name<span style={{ color: "red" }}>*</span>:
               </label>
-              <Select
+              <TextInput
                 themeScheme={themeScheme}
+                name={"target_repo_display_name"}
                 disabled={disabled}
-                defaultValue={
-                  availableParentOrgs.length >= 1
-                    ? availableParentOrgs[0].slug
-                    : initialValues?.target_org_slug
-                }
-                name={"target_org_slug"}
+                onChange={onDisplayNameInputChange}
+                placeholder={"i.e. My Super Project"}
                 required
                 style={styles.inputMaxWidth}
-              >
-                {availableParentOrgs.map((org) => (
-                  <option key={org.id} value={org.slug}>
-                    {org.displayName || org.slug}
-                  </option>
-                ))}
-              </Select>
+                type={"text"}
+                value={displayName}
+              />
             </Grid.Col>
-            {/* Repository Slug */}
+            <Grid.Row fluid nowrap alignItems={"center"} gap={16}>
+              {/* Parent Organization Select */}
+              <Grid.Col fluid nowrap gap={4}>
+                <label htmlFor={"target_org_slug"}>
+                  Owner Organization<span style={{ color: "red" }}>*</span>:
+                </label>
+                <Select
+                  themeScheme={themeScheme}
+                  disabled={disabled}
+                  defaultValue={
+                    availableParentOrgs.length >= 1
+                      ? availableParentOrgs[0].slug
+                      : initialValues?.target_org_slug
+                  }
+                  name={"target_org_slug"}
+                  required
+                  style={styles.inputMaxWidth}
+                >
+                  {availableParentOrgs.map((org) => (
+                    <option key={org.id} value={org.slug}>
+                      {org.displayName || org.slug}
+                    </option>
+                  ))}
+                </Select>
+              </Grid.Col>
+              {/* Repository Slug */}
+              <Grid.Col fluid nowrap gap={4}>
+                <label htmlFor={"target_repo_slug"}>
+                  Repository Slug<span style={{ color: "red" }}>*</span>:
+                </label>
+                <TextInput
+                  themeScheme={themeScheme}
+                  name={"target_repo_slug"}
+                  disabled={disabled}
+                  onChange={onSlugInputChange}
+                  placeholder={"i.e. my-super-project"}
+                  required
+                  style={styles.inputMaxWidth}
+                  type={"text"}
+                  value={slug}
+                />
+              </Grid.Col>
+            </Grid.Row>
+            {/* Repository Visibility */}
             <Grid.Col fluid nowrap gap={4}>
-              <label htmlFor={"target_repo_slug"}>
-                Repository Slug <span>(*)</span>:
+              <label htmlFor={"target_repo_visibility"}>
+                Repository Visibility<span style={{ color: "red" }}>*</span>:
               </label>
-              <TextInput
+              <Select
                 themeScheme={themeScheme}
-                name={"target_repo_slug"}
                 disabled={disabled}
-                onChange={onSlugInputChange}
-                placeholder={"i.e. my-super-project"}
-                required
+                defaultValue={
+                  initialValues?.target_repo_visibility || "PRIVATE"
+                }
+                name={"target_repo_visibility"}
                 style={styles.inputMaxWidth}
-                type={"text"}
-                value={slug}
-              />
+              >
+                <option key={"private"} value={"PRIVATE"}>
+                  Private
+                </option>
+                <option key={"unlisted"} value={"UNLISTED"}>
+                  Unlisted
+                </option>
+                <option key={"public"} value={"PUBLIC"}>
+                  Public
+                </option>
+              </Select>
             </Grid.Col>
-          </Grid.Row>
-          {/* Repository Visibility */}
-          <Grid.Col fluid nowrap gap={4}>
-            <label htmlFor={"target_repo_visibility"}>
-              Repository Visibility <span>(*)</span>:
-            </label>
-            <Select
-              themeScheme={themeScheme}
-              disabled={disabled}
-              defaultValue={initialValues?.target_repo_visibility || "PRIVATE"}
-              name={"target_repo_visibility"}
-              style={styles.inputMaxWidth}
-            >
-              <option key={"private"} value={"PRIVATE"}>
-                Private
-              </option>
-              <option key={"unlisted"} value={"UNLISTED"}>
-                Unlisted
-              </option>
-              <option key={"public"} value={"PUBLIC"}>
-                Public
-              </option>
-            </Select>
           </Grid.Col>
-        </Grid.Col>
-      </fieldset>
+        </Card>
+      </Grid.Col>
+
       {/* Submit Button */}
-      <Button
-        style={{ ...styles.inputMaxWidth, marginTop: 16 }}
-        type={"submit"}
-        disabled={disabled}
-      >
+      <Button style={styles.inputMaxWidth} type={"submit"} disabled={disabled}>
         Fork Repository!
       </Button>
-    </div>
+    </Grid.Col>
   );
 };
 

app/islands/RepositoryHero.tsx
@@ -6,9 +6,10 @@ import React from "react";
 import type { Organization, Repository } from "@prisma/client";
 // app
 import type { RepositoryForkedFromRepoMeta } from "../types";
+import { buildRouteLink } from "../utils/shared";
+import { ButtonAnchor } from "../components";
 import { AppRoute } from "../routes.defs";
 import { Grid } from "../components/Grid";
-import { buildRouteLink } from "../utils/shared";
 
 export interface RepositoryHeroProps {
   parentOrg: Organization;

...
@@ -17,6 +18,7 @@ export interface RepositoryHeroProps {
   forksCount?: number;
   path?: string;
   separator?: string;
+  showForkButton?: boolean;
 }
 
 const RepositoryHero: ReactIsland<RepositoryHeroProps> = ({

...
@@ -26,15 +28,12 @@ const RepositoryHero: ReactIsland<RepositoryHeroProps> = ({
   forksCount = 0,
   path = undefined,
   separator = "∙",
+  showForkButton = true,
 }) => {
   return (
-    <Grid.Col fluid>
+    <Grid.Col fluid gap={16}>
       <Grid.Row fluid alignItems={"center"}>
-        <Grid.Col
-          nowrap
-          flex={"1 0 468px"}
-          style={{ marginTop: 8, minWidth: 468 }}
-        >
+        <Grid.Col nowrap flex={"1 0 468px"} style={{ minWidth: 468 }}>
           <h1 style={{ margin: 0 }}>
             <a
               href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, {

...
@@ -86,32 +85,48 @@ const RepositoryHero: ReactIsland<RepositoryHeroProps> = ({
               </h5>
             )}
           </div>
-          <div style={{ marginTop: 16 }}>
-            <div>
-              <a
-                href={buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
-                  orgSlug: parentOrg.slug,
-                  repoSlug: repo.slug,
-                })}
-              >
-                Pull Requests
-              </a>
-            </div>
-          </div>
         </Grid.Col>
-        <Grid.Row nowrap style={{ minWidth: 90, marginTop: 8 }}>
-          <span>{forksCount}</span>
-          <a
+        {showForkButton && (
+          <ButtonAnchor
             href={buildRouteLink(AppRoute.REPOSITORY_FORK, {
               orgSlug: parentOrg.slug,
               repoSlug: repo.slug,
             })}
-            style={{ marginLeft: 8 }}
           >
-            Fork it!
-          </a>
-        </Grid.Row>
+            <Grid.Row
+              nowrap
+              justifyContent={"center"}
+              alignItems={"center"}
+              gap={8}
+            >
+              Fork
+              <span
+                style={{
+                  padding: "2px 6px",
+                  minWidth: 20,
+                  //
+                  background: "rgba(0,0,0,0.1)",
+                  borderRadius: 8,
+
+                  fontSize: 12,
+                }}
+              >
+                {forksCount}
+              </span>
+            </Grid.Row>
+          </ButtonAnchor>
+        )}
       </Grid.Row>
+      <Grid.Col fluid nowrap gap={16}>
+        <a
+          href={buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+            orgSlug: parentOrg.slug,
+            repoSlug: repo.slug,
+          })}
+        >
+          Pull Requests
+        </a>
+      </Grid.Col>
     </Grid.Col>
   );
 };

app/views/auth/LoginView.tsx
@@ -42,7 +42,11 @@ const LoginView: ReactView<LoginViewProps> = ({
         )}
         <Card
           themeScheme={commonProps.themeScheme}
-          style={{ marginTop: errorMessage != null ? 16 : 0, padding: 16 }}
+          style={{
+            maxWidth: 500,
+            marginTop: errorMessage != null ? 16 : 0,
+            padding: 16,
+          }}
         >
           <form
             method={"POST"}

app/views/auth/RegisterView.tsx
@@ -43,7 +43,11 @@ const RegisterView: ReactView<RegisterViewProps> = ({
         )}
         <Card
           themeScheme={commonProps.themeScheme}
-          style={{ marginTop: errorMessage != null ? 16 : 0, padding: 16 }}
+          style={{
+            maxWidth: 500,
+            marginTop: errorMessage != null ? 16 : 0,
+            padding: 16,
+          }}
         >
           <form
             method={"POST"}

app/views/repository/RepositoryCreateView.tsx
@@ -47,8 +47,9 @@ const RepositoryCreateView: ReactView<RepositoryCreateViewProps> = ({
         >
           <div data-islandid={`${RepositoryCreateForm.name}$$0`}>
             <RepositoryCreateForm
-              availableParentOrgs={availableParentOrgs}
               initialValues={initialValues}
+              availableParentOrgs={availableParentOrgs}
+              themeScheme={commonProps.themeScheme}
             />
           </div>
         </form>

app/views/repository/RepositoryForkView.tsx
@@ -44,6 +44,7 @@ const RepositoryForkView: ReactView<RepositoryForkViewProps> = ({
             path={`Fork`}
             parentOrg={sourceParentOrg}
             repo={sourceRepo}
+            showForkButton={false}
           />
         </IslandWrapper>
         <div style={{ height: 32 }} />

app/views/repository/RepositoryShowObjectView.tsx
@@ -11,6 +11,7 @@ import type {
   RepositoryObject,
   RepositoryWithForkedFromRepo,
 } from "../../types";
+import { NamedColors } from "../../utils/style";
 import {
   Card,
   Grid,

...
@@ -65,7 +66,18 @@ const RepositoryShowObjectView: ReactView<RepositoryShowObjectViewProps> = ({
 
         <Card
           data-islandid={`${RepositoryCommitSummaryLine.name}$$0`}
-          style={{ width: "100%", marginTop: 32, padding: 8, gap: 8 }}
+          style={{
+            width: "100%",
+            marginTop: 32,
+            padding: 8,
+            gap: 8,
+            backdropFilter: "blur(8px)",
+            backgroundColor: NamedColors.CARD_ALPHA_01[commonProps.themeScheme],
+            position: "sticky",
+            top: 80,
+            zIndex: 9000,
+            borderRadius: 8,
+          }}
           themeScheme={commonProps.themeScheme}
         >
           <RepositoryCommitSummaryLine

app/views/user/UserDetailsView.tsx
@@ -53,6 +53,12 @@ const UserDetailsView: ReactView<UserDetailsViewProps> = ({
           >
             Settings
           </ButtonAnchor>
+          <ButtonAnchor
+            href={buildRouteLink(AppRoute.AUTH_LOGOUT_ACTION, {})}
+            style={{ backgroundColor: "#f44d4d" }}
+          >
+            Logout
+          </ButtonAnchor>
         </Grid.Row>
         <IslandWrapper data-islandid={`${RepositoriesList.name}$$0`}>
           <RepositoriesList