Radish alpha
r
rad:z4D5UCArafTzTQpDZNQRuqswh3ury
Radicle desktop app
Radicle
Git
Make top-bar narrower
Open rudolfs opened 1 year ago

This also adds a back to home screen button and moves the breadcrumbs into the main content area.

check check-e2e

👉 Workflow runs 👉 Branch on GitHub

13 files changed +292 -269 0e427c7a 9fd2d489
modified src/components/Header.svelte
@@ -1,25 +1,26 @@
<script lang="ts">
  import type { Snippet } from "svelte";

+
  import * as router from "@app/lib/router";
  import { nodeRunning } from "@app/lib/events";

  import Icon from "./Icon.svelte";
  import NakedButton from "./NakedButton.svelte";
  import OutlineButton from "./OutlineButton.svelte";
+
  import Avatar from "./Avatar.svelte";

  interface Props {
-
    breadcrumbs: Snippet;
-
    columnSwitch?: Snippet;
+
    publicKey: string;
    center?: Snippet;
    settingsButton?: Snippet;
  }

-
  const { breadcrumbs, columnSwitch, center, settingsButton }: Props = $props();
+
  const { center, settingsButton, publicKey }: Props = $props();
</script>

<style>
  .header {
-
    height: 5rem;
+
    height: 3rem;
    padding: 0.5rem 1rem;
    display: flex;
    align-items: flex-start;
@@ -30,7 +31,7 @@
    top: 0;
    left: 0.5rem;
    right: 0.5rem;
-
    height: 5rem;
+
    height: 3rem;
    z-index: -1;
    background-color: var(--color-background-float);
    clip-path: var(--3px-bottom-corner-fill);
@@ -46,20 +47,6 @@
    width: 100%;
    justify-content: space-between;
  }
-
  .bottom-row {
-
    display: flex;
-
    gap: 0.5rem;
-
    font-size: var(--font-size-tiny);
-
    font-weight: var(--font-weight-semibold);
-
    align-items: center;
-

-
    min-height: 1.5rem;
-
    width: 100%;
-
    padding-left: 12px;
-
    /* Fixed height so that the navigation arrow buttons don't jump vertically
-
       when the column buttons aren't shown on the Home view vs Repo view. */
-
    height: 24px;
-
  }
</style>

<div class="header global-flex">
@@ -69,6 +56,15 @@
        <NakedButton
          variant="ghost"
          onclick={() => {
+
            void router.push({
+
              resource: "home",
+
            });
+
          }}>
+
          <Avatar {publicKey} />
+
        </NakedButton>
+
        <NakedButton
+
          variant="ghost"
+
          onclick={() => {
            window.history.back();
          }}>
          <Icon name="arrow-left" />
@@ -97,14 +93,5 @@
        </OutlineButton>
      </div>
    </div>
-

-
    <div class="bottom-row">
-
      {@render breadcrumbs()}
-
      {#if columnSwitch}
-
        <div style:margin-left="auto">
-
          {@render columnSwitch()}
-
        </div>
-
      {/if}
-
    </div>
  </div>
</div>
modified src/components/Icon.svelte
@@ -11,15 +11,18 @@
      | "checkmark"
      | "chevron-down"
      | "chevron-right"
+
      | "collapse-panel"
      | "comment"
      | "copy"
      | "cross"
      | "dashboard"
      | "delegate"
      | "diff"
+
      | "expand-panel"
      | "eye"
      | "face"
      | "file"
+
      | "home"
      | "inbox"
      | "issue"
      | "lock"
@@ -27,7 +30,6 @@
      | "moon"
      | "more-vertical"
      | "offline"
-
      | "one"
      | "online"
      | "patch"
      | "pen"
@@ -39,7 +41,6 @@
      | "seedling-filled"
      | "settings"
      | "sun"
-
      | "two"
      | "warning";
  }

@@ -140,6 +141,20 @@
    <path d="M7 10L8 10L8 11L7 11L7 10Z" />
    <path d="M9 8L10 8V9L9 9V8Z" />
    <path d="M8 9H9V10H8L8 9Z" />
+
  {:else if name === "collapse-panel"}
+
    <path d="M2 3.00002H3V13H2V3.00002Z" />
+
    <path d="M13 3.00002H14V6.00002H13V3.00002Z" />
+
    <path d="M13 10H14V13H13V10Z" />
+
    <path d="M5 2.00002H6V14H5V2.00002Z" />
+
    <path d="M3 2.00002H13V3.00002H3L3 2.00002Z" />
+
    <path d="M3 13H13V14H3L3 13Z" />
+
    <path d="M8 9.00002L8 8.00002H9V9.00002L8 9.00002Z" />
+
    <path d="M9 10L9 9.00002H10V10H9Z" />
+
    <path d="M9 7.00002V8.00002L10 8.00002V7.00002L9 7.00002Z" />
+
    <path d="M9 7.00002L14 7.00001V9.00001L9 9.00002V7.00002Z" />
+
    <path d="M10 5.00001H11V11H10V5.00001Z" />
+
    <path d="M9 6.00002H10V7.00002L9 7.00002L9 6.00002Z" />
+
    <path d="M8 7.00001L9 7.00002V8.00002H8L8 7.00001Z" />
  {:else if name === "comment"}
    <path d="M4 2H12V3H4V2Z" />
    <path d="M12 3L13 3V4H12V3Z" />
@@ -220,6 +235,20 @@
    <path d="M7 4H8V9H7V4Z" />
    <path d="M5 6H10V7H5V6Z" />
    <path d="M5 10H10V11H5V10Z" />
+
  {:else if name === "expand-panel"}
+
    <path d="M2 3.00002H3V13H2V3.00002Z" />
+
    <path d="M13 3.00002H14V5.00002H13V3.00002Z" />
+
    <path d="M13 11H14V13H13V11Z" />
+
    <path d="M5 2.00002H6V14H5V2.00002Z" />
+
    <path d="M3 2.00002H13V3.00002H3L3 2.00002Z" />
+
    <path d="M3 13H13V14H3L3 13Z" />
+
    <path d="M14 9.00002V8.00002H13V9.00002H14Z" />
+
    <path d="M13 10V9.00002H12V10H13Z" />
+
    <path d="M13 7.00002V8.00002H12V7.00002H13Z" />
+
    <path d="M13 7.00002L8 7.00002V9.00002L13 9.00002V7.00002Z" />
+
    <path d="M12 5.00002H11V11H12V5.00002Z" />
+
    <path d="M13 6.00002H12V7.00002H13V6.00002Z" />
+
    <path d="M14 7.00002H13V8.00002H14V7.00002Z" />
  {:else if name === "eye"}
    <path d="M10 5L8.00002 5V4L10 4V5Z" />
    <path d="M6.00002 11L8.00002 11L8.00002 12H6.00002L6.00002 11Z" />
@@ -278,6 +307,35 @@
    <path d="M4 2H9V3L4 3V2Z" />
    <path d="M13 6V13H12V6L13 6Z" />
    <path d="M4 3V13H3L3 3L4 3Z" />
+
  {:else if name === "home"}
+
    <path d="M7 1.50003H9V2.50003H7V1.50003Z" />
+
    <path d="M6 2.50003L7 2.50003V3.50003H6V2.50003Z" />
+
    <path d="M7 3.50003H8V4.50003H7V3.50003Z" />
+
    <path d="M9 2.50003L10 2.50003V3.50003H9V2.50003Z" />
+
    <path d="M8 3.50003L9 3.50003V4.50003H8V3.50003Z" />
+
    <path d="M10 3.50003L11 3.50003V4.50003H10L10 3.50003Z" />
+
    <path d="M9 4.50003L10 4.50003V5.50003H9L9 4.50003Z" />
+
    <path d="M11 4.50003L12 4.50003V5.50003H11V4.50003Z" />
+
    <path d="M10 5.50003L11 5.50003V6.50003H10V5.50003Z" />
+
    <path d="M12 5.50003H13V6.50003H12V5.50003Z" />
+
    <path d="M11 6.50003L12 6.50003V7.50003H11V6.50003Z" />
+
    <path d="M13 6.50003L14 6.50003V7.50003H13V6.50003Z" />
+
    <path d="M12 6.50003H13V7.50003H12V6.50003Z" />
+
    <path d="M12 7.50003H13V13.5H12V7.50003Z" />
+
    <path d="M3 7.50003H4V13.5H3V7.50003Z" />
+
    <path d="M5 3.50003L6 3.50003V4.50003H5V3.50003Z" />
+
    <path d="M6 4.50003L7 4.50003L7 5.50003H6V4.50003Z" />
+
    <path d="M4 4.50003H5V5.50003H4V4.50003Z" />
+
    <path d="M5 5.50003L6 5.50003L6 6.50003H5L5 5.50003Z" />
+
    <path d="M3 5.50003H4V6.50003H3V5.50003Z" />
+
    <path d="M3 6.50003L5 6.50003V7.50003L3 7.50003L3 6.50003Z" />
+
    <path d="M2 6.50003H3L3 7.50003L2 7.50003V6.50003Z" />
+
    <path d="M3 7.50003H4V8.50003H3V7.50003Z" />
+
    <path d="M4 13.5H7V14.5H4L4 13.5Z" />
+
    <path d="M9 13.5H12V14.5H9V13.5Z" />
+
    <path d="M6 10.5H7V13.5H6V10.5Z" />
+
    <path d="M7 9.50003H9V10.5L7 10.5L7 9.50003Z" />
+
    <path d="M9 10.5L10 10.5V13.5H9L9 10.5Z" />
  {:else if name === "inbox"}
    <path d="M2 3H3V13H2V3Z" />
    <path d="M13 3H14V13H13V3Z" />
@@ -403,15 +461,6 @@
    <path d="M4 11L5 11V12L4 12L4 11Z" />
    <path d="M3 12H4L4 13H3L3 12Z" />
    <path d="M2 13L3 13L3 14H2V13Z" />
-
  {:else if name === "one"}
-
    <path d="M2 3.00003H3V13H2V3.00003Z" />
-
    <path d="M13 3.00003H14V13H13V3.00003Z" />
-
    <path d="M3 2.00003H13V3.00003H3L3 2.00003Z" />
-
    <path d="M3 13H13V14H3L3 13Z" />
-
    <path d="M8 5.00003H9V11H8V5.00003Z" />
-
    <path d="M6 7.00003H7V8.00003H6V7.00003Z" />
-
    <path d="M7 6.00003H8V7.00003H7V6.00003Z" />
-
    <path d="M6 10H11V11H6V10Z" />
  {:else if name === "online"}
    <path d="M3 5.99999L3 7.99999H2L2 5.99999H3Z" />
    <path d="M13 9.99998V7.99998H14V9.99998H13Z" />
@@ -650,32 +699,6 @@
    <path d="M6 9L7 9L7 10H6V9Z" />
    <path d="M9 9L10 9L10 10H9L9 9Z" />
    <path d="M9 6H10V7H9V6Z" />
-
  {:else if name === "two"}
-
    <path d="M2 3.00003H3V13H2V3.00003Z" />
-
    <path d="M13 3.00003H14V13H13V3.00003Z" />
-
    <path d="M6 2.00003H3L3 3.00003L6 3.00003V2.00003Z" />
-
    <path d="M10 2.00003H13V3.00003L10 3.00003V2.00003Z" />
-
    <path d="M10 13H13V14H10V13Z" />
-
    <path d="M3 13H6V14H3L3 13Z" />
-
    <path d="M2 3.00003H3V13H2V3.00003Z" />
-
    <path d="M13 3.00003H14V13H13V3.00003Z" />
-
    <path d="M6 3.00003L7 3.00003V4.00003H6V3.00003Z" />
-
    <path d="M6 12H7V13H6L6 12Z" />
-
    <path d="M9 3.00003L10 3.00003V4.00003H9V3.00003Z" />
-
    <path d="M9 12H10V13L9 13V12Z" />
-
    <path d="M7 2.00003L3 2.00003L3 3.00003L7 3.00003V2.00003Z" />
-
    <path d="M9 2.00003L13 2.00003V3.00003L9 3.00003L9 2.00003Z" />
-
    <path d="M9 13L13 13V14H9L9 13Z" />
-
    <path d="M3 13H7L7 14H3L3 13Z" />
-
    <path d="M6 5.00003H10V6.00003H6V5.00003Z" />
-
    <path d="M6 9.00003H8V10H6V9.00003Z" />
-
    <path d="M5 10H6V11H5V10Z" />
-
    <path d="M6 10H7V11H6V10Z" />
-
    <path d="M7 10H8V11H7V10Z" />
-
    <path d="M6 10H11V11H6V10Z" />
-
    <path d="M10 6.00003L11 6.00003V8.00003H10V6.00003Z" />
-
    <path d="M5 6.00003H6V7.00003H5V6.00003Z" />
-
    <path d="M8 8.00003H10V9.00003L8 9.00003L8 8.00003Z" />
  {:else if name === "warning"}
    <path d="M7 2H9V3H7V2Z" />
    <path d="M6 3H7V5H6V3Z" />
modified src/components/Link.svelte
@@ -10,6 +10,7 @@
    disabled?: boolean;
    underline?: boolean;
    styleWidth?: string;
+
    styleColor?: string;
  }

  const {
@@ -18,6 +19,7 @@
    disabled = false,
    underline = true,
    styleWidth,
+
    styleColor,
  }: Props = $props();

  function navigateToRoute(event: MouseEvent): void {
@@ -46,6 +48,7 @@
  onclick={navigateToRoute}
  href={routeToPath(route)}
  class:underline
+
  style:color={styleColor}
  style:width={styleWidth}>
  {@render children()}
</a>
modified src/components/PatchesSecondColumn.svelte
@@ -91,7 +91,7 @@
      <Link
        styleWidth="100%"
        underline={false}
-
        route={{ resource: "repo.patches", rid: repo.rid, status }}>
+
        route={{ resource: "repo.patches", rid: repo.rid, status: undefined }}>
        <div class="tab active">
          <div class="global-flex"><Icon name="patch" />Patches</div>
          <div class="global-counter">
modified src/components/Sidebar.svelte
@@ -5,9 +5,12 @@
  import { patchStatusColor } from "@app/lib/utils";
  import { issueStatusColor } from "@app/lib/utils";

+
  import { storeLayout, getLayout } from "@app/views/repo/Layout.svelte";
+

  import Icon from "@app/components/Icon.svelte";
  import Settings from "@app/components/Settings.svelte";
  import Border from "./Border.svelte";
+
  import NakedButton from "./NakedButton.svelte";

  interface Props {
    activeTab:
@@ -115,8 +118,27 @@
  {/if}
</div>

-
<Settings
-
  popoverProps={{
-
    popoverPositionBottom: "3rem",
-
    popoverPositionLeft: "0",
-
  }} />
+
<div>
+
  <NakedButton
+
    styleHeight="40px"
+
    variant="ghost"
+
    onclick={() => {
+
      if (getLayout()) {
+
        storeLayout("two-column");
+
      } else {
+
        storeLayout("one-column");
+
      }
+
    }}>
+
    {#if getLayout()}
+
      <Icon name="expand-panel" />
+
    {:else}
+
      <Icon name="collapse-panel" />
+
    {/if}
+
  </NakedButton>
+

+
  <Settings
+
    popoverProps={{
+
      popoverPositionBottom: "3rem",
+
      popoverPositionLeft: "0",
+
    }} />
+
</div>
modified src/views/Home.svelte
@@ -6,7 +6,6 @@

  import CopyableId from "@app/components/CopyableId.svelte";
  import Header from "@app/components/Header.svelte";
-
  import NodeId from "@app/components/NodeId.svelte";
  import RepoCard from "@app/components/RepoCard.svelte";
  import Settings from "@app/components/Settings.svelte";

@@ -41,17 +40,10 @@

<div style:height="fit-content">
  <div class="header">
-
    <Header>
+
    <Header publicKey={config.publicKey}>
      {#snippet center()}
        <CopyableId id={`did:key:${config.publicKey}`} />
      {/snippet}
-
      {#snippet breadcrumbs()}
-
        <NodeId
-
          publicKey={config.publicKey}
-
          alias={config.alias}
-
          styleFontFamily="var(--font-family-sans-serif)"
-
          styleFontSize="var(--font-size-tiny)" />
-
      {/snippet}
      {#snippet settingsButton()}
        <Settings
          styleHeight="32px"
modified src/views/repo/CreateIssue.svelte
@@ -19,9 +19,7 @@
  import InlineTitle from "@app/components/InlineTitle.svelte";
  import IssueSecondColumn from "@app/components/IssueSecondColumn.svelte";
  import LabelInput from "@app/components/LabelInput.svelte";
-
  import Link from "@app/components/Link.svelte";
  import Markdown from "@app/components/Markdown.svelte";
-
  import NodeId from "@app/components/NodeId.svelte";
  import OutlineButton from "@app/components/OutlineButton.svelte";
  import Sidebar from "@app/components/Sidebar.svelte";
  import TextInput from "@app/components/TextInput.svelte";
@@ -66,8 +64,6 @@
      status,
    });
  }
-

-
  const project = $derived(repo.payloads["xyz.radicle.project"]!);
</script>

<style>
@@ -106,29 +102,7 @@
  }
</style>

-
<Layout>
-
  {#snippet breadcrumbs()}
-
    <Link route={{ resource: "home" }}>
-
      <NodeId
-
        publicKey={config.publicKey}
-
        alias={config.alias}
-
        styleFontFamily="var(--font-family-sans-serif)"
-
        styleFontSize="var(--font-size-tiny)" />
-
    </Link>
-
    <Link route={{ resource: "repo.issues", rid: repo.rid, status: "open" }}>
-
      <div class="global-flex">
-
        <Icon name="chevron-right" />
-
        {project.data.name}
-
      </div>
-
    </Link>
-
    <Icon name="chevron-right" />
-
    <Link route={{ resource: "repo.issues", rid: repo.rid, status: "open" }}>
-
      Issues
-
    </Link>
-
    <Icon name="chevron-right" />
-
    New Issue
-
  {/snippet}
-

+
<Layout publicKey={config.publicKey}>
  {#snippet sidebar()}
    <Sidebar activeTab={{ type: "issues", status }} rid={repo.rid} />
  {/snippet}
modified src/views/repo/Issue.svelte
@@ -367,35 +367,20 @@
    margin-bottom: 0.5rem;
    color: var(--color-foreground-dim);
  }
+
  .breadcrumbs {
+
    display: flex;
+
    gap: 0.5rem;
+
    font-size: var(--font-size-tiny);
+
    font-weight: var(--font-weight-semibold);
+
    align-items: center;
+
    min-height: 1.5rem;
+
    width: 100%;
+
    margin-bottom: 1rem;
+
    color: var(--color-foreground-dim);
+
  }
</style>

-
<Layout>
-
  {#snippet breadcrumbs()}
-
    <div class="global-flex txt-overflow">
-
      <Link route={{ resource: "home" }}>
-
        <NodeId
-
          publicKey={config.publicKey}
-
          alias={config.alias}
-
          styleFontFamily="var(--font-family-sans-serif)"
-
          styleFontSize="var(--font-size-tiny)" />
-
      </Link>
-
      <Link route={{ resource: "repo.issues", rid: repo.rid, status: "open" }}>
-
        <div class="global-flex">
-
          <Icon name="chevron-right" />
-
          {project.data.name}
-
        </div>
-
      </Link>
-
      <Icon name="chevron-right" />
-
      <Link route={{ resource: "repo.issues", rid: repo.rid, status: "open" }}>
-
        Issues
-
      </Link>
-
      <Icon name="chevron-right" />
-
      <div class="txt-overflow">
-
        {issue.title}
-
      </div>
-
    </div>
-
  {/snippet}
-

+
<Layout publicKey={config.publicKey}>
  {#snippet headerCenter()}
    <CopyableId id={issue.id} />
  {/snippet}
@@ -409,7 +394,7 @@
  {/snippet}

  <div class="content">
-
    <div style:margin-bottom="1rem" style:margin-top="-6px">
+
    <div style:margin-bottom="0.5rem" style:margin-top="-6px">
      {#if editingTitle}
        <div class="title">
          <TextInput
@@ -455,6 +440,32 @@
      {/if}
    </div>

+
    <div class="breadcrumbs txt-overflow">
+
      <Link route={{ resource: "home" }}>
+
        <NodeId
+
          publicKey={config.publicKey}
+
          alias={config.alias}
+
          styleFontFamily="var(--font-family-sans-serif)"
+
          styleFontSize="var(--font-size-tiny)" />
+
      </Link>
+
      <Icon name="chevron-right" />
+
      <Link
+
        route={{ resource: "repo.issues", rid: repo.rid, status: "open" }}
+
        styleColor="var(--color-foreground-dim)">
+
        {project.data.name}
+
      </Link>
+
      <Icon name="chevron-right" />
+
      <Link
+
        route={{ resource: "repo.issues", rid: repo.rid, status: "open" }}
+
        styleColor="var(--color-foreground-dim)">
+
        Issues
+
      </Link>
+
      <Icon name="chevron-right" />
+
      <div class="txt-overflow">
+
        {issue.title}
+
      </div>
+
    </div>
+

    <Border variant="ghost" styleGap="0">
      <div class="metadata-section" style:min-width="8rem">
        <div class="metadata-section-title">Status</div>
modified src/views/repo/Issues.svelte
@@ -40,31 +40,28 @@
    font-weight: var(--font-weight-medium);
    font-size: var(--font-size-medium);
    display: flex;
-
    padding: 0 1rem 1rem 1rem;
+
    padding: 0 1rem 0.5rem 1rem;
    align-items: center;
    justify-content: space-between;
  }
+
  .breadcrumbs {
+
    display: flex;
+
    gap: 0.5rem;
+
    font-size: var(--font-size-tiny);
+
    font-weight: var(--font-weight-semibold);
+
    align-items: center;
+
    min-height: 1.5rem;
+
    width: 100%;
+
    margin-bottom: 1rem;
+
    padding-left: 1rem;
+
    color: var(--color-foreground-dim);
+
  }
</style>

-
<Layout hideSidebar styleSecondColumnOverflow="visible">
-
  {#snippet breadcrumbs()}
-
    <Link route={{ resource: "home" }}>
-
      <NodeId
-
        publicKey={config.publicKey}
-
        alias={config.alias}
-
        styleFontFamily="var(--font-family-sans-serif)"
-
        styleFontSize="var(--font-size-tiny)" />
-
    </Link>
-
    <Link route={{ resource: "repo.issues", rid: repo.rid, status: "open" }}>
-
      <div class="global-flex">
-
        <Icon name="chevron-right" />
-
        {project.data.name}
-
      </div>
-
    </Link>
-
    <Icon name="chevron-right" />
-
    Issues
-
  {/snippet}
-

+
<Layout
+
  hideSidebar
+
  styleSecondColumnOverflow="visible"
+
  publicKey={config.publicKey}>
  {#snippet headerCenter()}
    <CopyableId id={repo.rid} />
  {/snippet}
@@ -96,6 +93,24 @@
    </div>
  </div>

+
  <div class="breadcrumbs">
+
    <Link route={{ resource: "home" }}>
+
      <NodeId
+
        publicKey={config.publicKey}
+
        alias={config.alias}
+
        styleFontFamily="var(--font-family-sans-serif)"
+
        styleFontSize="var(--font-size-tiny)" />
+
    </Link>
+
    <Icon name="chevron-right" />
+
    <Link
+
      route={{ resource: "repo.issues", rid: repo.rid, status: "open" }}
+
      styleColor="var(--color-foreground-dim)">
+
      {project.data.name}
+
    </Link>
+
    <Icon name="chevron-right" />
+
    Issues
+
  </div>
+

  <div class="list">
    {#each issues as issue}
      <IssueTeaser {issue} rid={repo.rid} {status} />
modified src/views/repo/Layout.svelte
@@ -1,15 +1,38 @@
+
<script lang="ts" module>
+
  type LayoutState = "one-column" | "two-column";
+

+
  const LAYOUT_KEY = "one-column-layout-enabled";
+

+
  let oneColumnLayout = $state(
+
    localStorage ? localStorage.getItem(LAYOUT_KEY) === "one-column" : false,
+
  );
+

+
  export function getLayout() {
+
    return oneColumnLayout;
+
  }
+

+
  export function storeLayout(newValue: LayoutState): void {
+
    oneColumnLayout = newValue === "one-column";
+
    if (localStorage) {
+
      localStorage.setItem(LAYOUT_KEY, newValue);
+
    } else {
+
      console.warn(
+
        "localStorage isn't available, not able to persist the selected layout settings without it.",
+
      );
+
    }
+
  }
+
</script>
+

<script lang="ts">
  import type { Snippet } from "svelte";
-
  type LayoutState = "one-column" | "two-column";

  import { onMount } from "svelte";

  import Header from "@app/components/Header.svelte";
-
  import Icon from "@app/components/Icon.svelte";

  interface Props {
    children: Snippet;
-
    breadcrumbs: Snippet;
+
    publicKey: string;
    headerCenter?: Snippet;
    secondColumn: Snippet;
    sidebar: Snippet;
@@ -21,7 +44,7 @@

  const {
    children,
-
    breadcrumbs,
+
    publicKey,
    headerCenter = undefined,
    secondColumn,
    sidebar,
@@ -31,27 +54,11 @@
    styleSecondColumnOverflow = "scroll",
  }: Props = $props();

-
  const LAYOUT_KEY = "one-column-layout-enabled";
-

-
  let oneColumnLayout = $state(
-
    localStorage ? localStorage.getItem(LAYOUT_KEY) === "one-column" : false,
-
  );
  let contentContainer: HTMLElement | undefined = $state();
  let secondColumnContainer: HTMLElement | undefined = $state();
  let loadingContent = false;
  let loadingSecondColumn = false;

-
  function storeLayout(newValue: LayoutState): void {
-
    oneColumnLayout = newValue === "one-column";
-
    if (localStorage) {
-
      localStorage.setItem(LAYOUT_KEY, newValue);
-
    } else {
-
      console.warn(
-
        "localStorage isn't available, not able to persist the selected layout settings without it.",
-
      );
-
    }
-
  }
-

  onMount(() => {
    if (contentContainer && loadMoreContent) {
      contentContainer.addEventListener("scroll", async () => {
@@ -126,65 +133,21 @@
    overflow: scroll;
    overscroll-behavior: none;
  }
-

-
  .column-radio {
-
    display: flex;
-
    background-color: var(--color-background-dip);
-
    clip-path: var(--1px-corner-fill);
-
    gap: 2px;
-
  }
-
  .toggle {
-
    cursor: pointer;
-
    border: 0;
-
    height: 24px;
-
    clip-path: var(--1px-corner-fill);
-
    margin: 0;
-
    background-color: var(--color-fill-ghost);
-
    color: var(--color-foreground-active);
-
  }
-
  .toggle:hover,
-
  .toggle.active {
-
    background: none;
-
    color: var(--color-foreground-emphasized);
-
  }
</style>

<div class="layout">
  <div class="header">
-
    <Header {breadcrumbs} center={headerCenter}>
-
      {#snippet columnSwitch()}
-
        <div class="column-radio">
-
          <button
-
            class="toggle"
-
            class:active={oneColumnLayout}
-
            onclick={() => {
-
              storeLayout("one-column");
-
            }}>
-
            <Icon name="one" />
-
          </button>
-
          <button
-
            class="toggle"
-
            class:active={!oneColumnLayout}
-
            onclick={() => {
-
              storeLayout("two-column");
-
            }}>
-
            <Icon name="two" />
-
          </button>
-
        </div>
-
      {/snippet}
-
    </Header>
+
    <Header {publicKey} center={headerCenter}></Header>
  </div>

-
  <div
-
    class="sidebar"
-
    style:display={hideSidebar && !oneColumnLayout ? "none" : "flex"}>
+
  <div class="sidebar" style:display={hideSidebar ? "none" : "flex"}>
    {@render sidebar()}
  </div>

  <div
    class="secondColumn"
    bind:this={secondColumnContainer}
-
    style:display={oneColumnLayout ? "none" : undefined}
+
    style:display={oneColumnLayout && !hideSidebar ? "none" : undefined}
    style:overflow={styleSecondColumnOverflow}>
    {@render secondColumn()}
  </div>
modified src/views/repo/Patch.svelte
@@ -90,7 +90,7 @@
    font-weight: var(--font-weight-medium);
    -webkit-user-select: text;
    user-select: text;
-
    margin-bottom: 1rem;
+
    margin-bottom: 0.5rem;
    margin-top: 0.35rem;
  }
  .patch-list {
@@ -120,31 +120,20 @@
    height: 100%;
    top: 0;
  }
+
  .breadcrumbs {
+
    display: flex;
+
    gap: 0.5rem;
+
    font-size: var(--font-size-tiny);
+
    font-weight: var(--font-weight-semibold);
+
    align-items: center;
+
    min-height: 1.5rem;
+
    width: 100%;
+
    margin-bottom: 1rem;
+
    color: var(--color-foreground-dim);
+
  }
</style>

-
<Layout {loadMoreSecondColumn}>
-
  {#snippet breadcrumbs()}
-
    <Link route={{ resource: "home" }}>
-
      <NodeId
-
        publicKey={config.publicKey}
-
        alias={config.alias}
-
        styleFontFamily="var(--font-family-sans-serif)"
-
        styleFontSize="var(--font-size-tiny)" />
-
    </Link>
-
    <Link route={{ resource: "repo.patches", rid: repo.rid, status: "open" }}>
-
      <div class="global-flex">
-
        <Icon name="chevron-right" />
-
        {project.data.name}
-
      </div>
-
    </Link>
-
    <Icon name="chevron-right" />
-
    <Link route={{ resource: "repo.patches", rid: repo.rid, status: "open" }}>
-
      Patches
-
    </Link>
-
    <Icon name="chevron-right" />
-
    {patch.title}
-
  {/snippet}
-

+
<Layout {loadMoreSecondColumn} publicKey={config.publicKey}>
  {#snippet headerCenter()}
    <CopyableId id={patch.id} />
  {/snippet}
@@ -177,6 +166,31 @@
    <div class="title">
      <InlineTitle content={patch.title} fontSize="medium" />
    </div>
+

+
    <div class="breadcrumbs">
+
      <Link route={{ resource: "home" }}>
+
        <NodeId
+
          publicKey={config.publicKey}
+
          alias={config.alias}
+
          styleFontFamily="var(--font-family-sans-serif)"
+
          styleFontSize="var(--font-size-tiny)" />
+
      </Link>
+
      <Icon name="chevron-right" />
+
      <Link
+
        route={{ resource: "repo.patches", rid: repo.rid, status: "open" }}
+
        styleColor="var(--color-foreground-dim)">
+
        {project.data.name}
+
      </Link>
+
      <Icon name="chevron-right" />
+
      <Link
+
        route={{ resource: "repo.patches", rid: repo.rid, status: "open" }}
+
        styleColor="var(--color-foreground-dim)">
+
        Patches
+
      </Link>
+
      <Icon name="chevron-right" />
+
      {patch.title}
+
    </div>
+

    <div class="txt-small patch-body">
      <CommentComponent
        caption="opened"
modified src/views/repo/Patches.svelte
@@ -63,32 +63,30 @@
  .header {
    font-weight: var(--font-weight-medium);
    font-size: var(--font-size-medium);
-
    padding: 0 1rem 1rem 1rem;
+
    padding: 0 1rem 0.5rem 1rem;
    display: flex;
    align-items: center;
-
    height: 50px;
+
    height: 42px;
+
  }
+
  .breadcrumbs {
+
    display: flex;
+
    gap: 0.5rem;
+
    font-size: var(--font-size-tiny);
+
    font-weight: var(--font-weight-semibold);
+
    align-items: center;
+
    min-height: 1.5rem;
+
    width: 100%;
+
    margin-bottom: 1rem;
+
    padding-left: 1rem;
+
    color: var(--color-foreground-dim);
  }
</style>

-
<Layout {loadMoreContent} hideSidebar styleSecondColumnOverflow="visible">
-
  {#snippet breadcrumbs()}
-
    <Link route={{ resource: "home" }}>
-
      <NodeId
-
        publicKey={config.publicKey}
-
        alias={config.alias}
-
        styleFontFamily="var(--font-family-sans-serif)"
-
        styleFontSize="var(--font-size-tiny)" />
-
    </Link>
-
    <Link route={{ resource: "repo.issues", rid: repo.rid, status: "open" }}>
-
      <div class="global-flex">
-
        <Icon name="chevron-right" />
-
        {project.data.name}
-
      </div>
-
    </Link>
-
    <Icon name="chevron-right" />
-
    Patches
-
  {/snippet}
-

+
<Layout
+
  {loadMoreContent}
+
  hideSidebar
+
  styleSecondColumnOverflow="visible"
+
  publicKey={config.publicKey}>
  {#snippet headerCenter()}
    <CopyableId id={repo.rid} />
  {/snippet}
@@ -105,6 +103,23 @@

  <div class="header">Patches</div>

+
  <div class="breadcrumbs">
+
    <Link route={{ resource: "home" }}>
+
      <NodeId
+
        publicKey={config.publicKey}
+
        alias={config.alias}
+
        styleFontFamily="var(--font-family-sans-serif)"
+
        styleFontSize="var(--font-size-tiny)" />
+
    </Link>
+
    <Icon name="chevron-right" />
+
    <Link
+
      route={{ resource: "repo.issues", rid: repo.rid, status: "open" }}
+
      styleColor="var(--color-foreground-dim)">
+
      {project.data.name}
+
    </Link>
+
    <Icon name="chevron-right" />
+
    Patches
+
  </div>
  <div class="list">
    {#each items as patch}
      <PatchTeaser rid={repo.rid} {patch} {status} />
modified tests/e2e/authenticate.spec.ts
@@ -5,7 +5,9 @@ test("removing identities from ssh-agent and re-adding them", async ({
  peer,
}) => {
  await page.goto("/");
-
  await expect(page.getByText("palm")).toBeVisible();
+
  await expect(
+
    page.getByText("did:key:z6MktULudTtAsAhRegYPiZ6631RV3viv12qd4GQF8z1xB22S"),
+
  ).toBeVisible();

  await peer.logOut();
  await expect(
@@ -13,5 +15,7 @@ test("removing identities from ssh-agent and re-adding them", async ({
  ).toBeVisible();

  await peer.authenticate();
-
  await expect(page.getByText("palm")).toBeVisible();
+
  await expect(
+
    page.getByText("did:key:z6MktULudTtAsAhRegYPiZ6631RV3viv12qd4GQF8z1xB22S"),
+
  ).toBeVisible();
});