Radish alpha
r
Radicle desktop app
Radicle
Git (anonymous pull)
Log in to clone via SSH
Style patch tabs
Rūdolfs Ošiņš committed 1 year ago
commit 63ec8cb473054fbdf325f92a8e8158f37abec615
parent 6326863f21de2d20f49f446a1d424e330602e3ac
5 files changed +236 -106
modified src/components/Border.svelte
@@ -11,10 +11,12 @@
    styleHeight?: string;
    styleMinHeight?: string;
    styleWidth?: string;
+
    styleDisplay?: string;
    styleCursor?: "default" | "pointer" | "text";
    styleGap?: string;
    styleOverflow?: string;
    flatTop?: boolean;
+
    flatBottom?: boolean;
    styleBackgroundColor?: string;
    styleFlexDirection?: string;
    styleAlignItems?: string;
@@ -31,10 +33,12 @@
    styleMinHeight,
    stylePosition,
    styleWidth,
+
    styleDisplay = "flex",
    styleCursor = "default",
    styleGap = "0.5rem",
    styleOverflow,
    flatTop = false,
+
    flatBottom = false,
    styleBackgroundColor = "var(--color-background-default)",
    styleFlexDirection = "row",
    styleAlignItems = "center",
@@ -130,7 +134,6 @@
  }
  .p3-3 {
    grid-area: p3-3;
-
    display: flex;
    background-color: var(--local-background-color);
  }
  .p3-4 {
@@ -196,6 +199,21 @@
  .flat-top > .p2-5 {
    background-color: var(--local-button-color-1);
  }
+

+
  .flat-bottom > .p4-2,
+
  .flat-bottom > .p4-4 {
+
    background-color: transparent;
+
  }
+

+
  .flat-bottom > .p4-1,
+
  .flat-bottom > .p4-5,
+
  .flat-bottom > .p5-3,
+
  .flat-bottom > .p5-1,
+
  .flat-bottom > .p5-2,
+
  .flat-bottom > .p5-4,
+
  .flat-bottom > .p5-5 {
+
    background-color: var(--local-button-color-1);
+
  }
</style>

<!-- svelte-ignore a11y_click_events_have_key_events -->
@@ -204,6 +222,7 @@
  style:cursor={styleCursor}
  class="container"
  class:flat-top={flatTop}
+
  class:flat-bottom={flatBottom}
  {onclick}
  role="button"
  tabindex={onclick !== undefined ? 0 : -1}
@@ -226,6 +245,7 @@
  <div class="p3-2"></div>
  <div
    class="p3-3"
+
    style:display={styleDisplay}
    style:position={stylePosition}
    style:padding={stylePadding}
    style:gap={styleGap}
modified src/components/Changeset.svelte
@@ -16,11 +16,15 @@
    display: flex;
    flex-direction: column;
  }
+

+
  .diff:not(:last-of-type) {
+
    margin-bottom: 1rem;
+
  }
</style>

<div class="diff-list">
  {#each diff.files as file}
-
    <div style:margin-bottom="1rem">
+
    <div class="diff">
      <FileDiff
        filePath={"path" in file ? file.path : file.newPath}
        oldFilePath={"oldPath" in file ? file.oldPath : undefined}
modified src/components/File.svelte
@@ -13,9 +13,9 @@
<style>
  .header {
    display: flex;
-
    height: 3rem;
    align-items: center;
-
    padding: 0 0.5rem 0 1rem;
+
    height: 2.5rem;
+
    padding-left: 1rem;
    z-index: 2;
    font-size: var(--font-size-small);
  }
@@ -46,6 +46,7 @@
  .container {
    position: relative;
    overflow-x: auto;
+
    z-index: 1;
  }
  .container::after {
    position: absolute;
added src/components/Tab.svelte
@@ -0,0 +1,75 @@
+
<script lang="ts">
+
  import type { Snippet } from "svelte";
+

+
  interface Props {
+
    children: Snippet;
+
    onclick?: () => void;
+
    disabled?: boolean;
+
    active?: boolean;
+
    flatLeft?: boolean;
+
    flatRight?: boolean;
+
  }
+

+
  const {
+
    children,
+
    onclick = undefined,
+
    disabled = false,
+
    active = false,
+
    flatLeft = false,
+
    flatRight = false,
+
  }: Props = $props();
+
</script>
+

+
<style>
+
  .container {
+
    white-space: nowrap;
+

+
    -webkit-touch-callout: none;
+
    -webkit-user-select: none;
+
    user-select: none;
+
    display: flex;
+
    flex-direction: row;
+
    font-size: var(--font-size-small);
+
  }
+

+
  .wrapper {
+
    position: relative;
+
    display: flex;
+
    gap: 0.5rem;
+
    padding: 5px 0;
+
  }
+

+
  .active {
+
    font-weight: var(--font-weight-semibold);
+
    color: var(--color-foreground-emphasized);
+
  }
+

+
  .wrapper.active::after {
+
    position: absolute;
+
    z-index: 1;
+
    content: " ";
+
    background-color: var(--color-fill-secondary);
+
    height: 2px;
+
    bottom: -4px;
+
    width: 100%;
+
  }
+

+
  .container.disabled {
+
    color: var(--color-foreground-disabled);
+
  }
+
</style>
+

+
<!-- svelte-ignore a11y_click_events_have_key_events -->
+
<div
+
  class="container"
+
  style:cursor={!disabled ? "pointer" : "default"}
+
  class:disabled
+
  class:flat-right={flatRight}
+
  class:flat-left={flatLeft}
+
  onclick={!disabled ? onclick : undefined}
+
  role="button"
+
  tabindex="0">
+
  <div class="wrapper" class:active>
+
    {@render children()}
+
  </div>
+
</div>
modified src/views/repo/Patch.svelte
@@ -27,7 +27,6 @@

  import AssigneeInput from "@app/components/AssigneeInput.svelte";
  import Border from "@app/components/Border.svelte";
-
  import Button from "@app/components/Button.svelte";
  import Changeset from "@app/components/Changeset.svelte";
  import CommentComponent from "@app/components/Comment.svelte";
  import CopyableId from "@app/components/CopyableId.svelte";
@@ -40,6 +39,7 @@
  import PatchTeaser from "@app/components/PatchTeaser.svelte";
  import PatchTimeline from "@app/components/PatchTimeline.svelte";
  import Sidebar from "@app/components/Sidebar.svelte";
+
  import Tab from "@app/components/Tab.svelte";
  import TextInput from "@app/components/TextInput.svelte";

  interface Props {
@@ -335,8 +335,9 @@
  }

  .patch-body {
-
    margin: 1rem 0;
+
    margin-bottom: 1rem;
    position: relative;
+
    z-index: 1;
  }
  /* We put the background and clip-path in a separate element to prevent
     popovers being clipped in the main element. */
@@ -471,113 +472,142 @@
      {/if}
    </div>

-
    <Border variant="ghost" styleGap="0">
-
      <div class="metadata-section" style:min-width="8rem">
-
        <div class="metadata-section-title">Status</div>
-
        <PatchStateBadge state={patch.state} />
-
      </div>
-

-
      <div class="metadata-divider"></div>
-

-
      <div class="metadata-section" style:flex="1">
-
        <LabelInput
-
          allowedToEdit={!!roles.isDelegateOrAuthor(
-
            config.publicKey,
-
            repo.delegates.map(delegate => delegate.did),
-
            patch.author.did,
-
          )}
-
          labels={patch.labels}
-
          submitInProgress={labelSaveInProgress}
-
          save={saveLabels} />
-
      </div>
-

-
      <div class="metadata-divider"></div>
-

-
      <div class="metadata-section" style:flex="1">
-
        <AssigneeInput
-
          allowedToEdit={!!roles.isDelegateOrAuthor(
-
            config.publicKey,
-
            repo.delegates.map(delegate => delegate.did),
-
            patch.author.did,
-
          )}
-
          assignees={patch.assignees}
-
          submitInProgress={assigneesSaveInProgress}
-
          save={saveAssignees} />
-
      </div>
-
    </Border>
-

-
    <div class="global-flex" style:gap="0" style:margin-top="1rem">
-
      <Button
-
        flatRight
-
        active={tab === "patch"}
-
        variant="ghost"
-
        onclick={() => {
-
          tab = "patch";
-
        }}>
-
        Patch
-
      </Button>
-

-
      <Button
-
        flatLeft
-
        variant="ghost"
-
        active={tab === "revisions"}
-
        onclick={() => {
-
          tab = "revisions";
-
        }}>
-
        Revision: {formatOid(revisions.slice(-1)[0].id)}
-
        <span class="global-counter" style:height="22px">latest</span>
-
      </Button>
+
    <div class="global-flex" style:gap="0.5rem">
+
      <Border stylePosition="relative" variant="ghost" flatBottom>
+
        <div
+
          class="global-flex"
+
          style:z-index="10"
+
          style:gap="1rem"
+
          style:padding="0 1rem">
+
          <Tab
+
            active={tab === "patch"}
+
            onclick={() => {
+
              tab = "patch";
+
            }}>
+
            {formatOid(patch.id)}
+
            <span
+
              class="global-counter"
+
              style:height="22px"
+
              style:color="var(--color-foreground-contrast)">
+
              Initial
+
            </span>
+
          </Tab>
+

+
          <Tab
+
            active={tab === "revisions"}
+
            onclick={() => {
+
              tab = "revisions";
+
            }}>
+
            {formatOid(revisions.slice(-1)[0].id)}
+
            <span
+
              class="global-counter"
+
              style:height="22px"
+
              style:color="var(--color-foreground-contrast)">
+
              Latest
+
            </span>
+
          </Tab>
+
        </div>
+
      </Border>
    </div>

    {#if tab === "patch"}
-
      <div class="txt-small patch-body">
-
        <CommentComponent
-
          caption="opened"
-
          rid={repo.rid}
-
          id={patch.id}
-
          lastEdit={revisions[0].description.length > 1
-
            ? revisions[0].description.at(-1)
-
            : undefined}
-
          author={revisions[0].author}
-
          reactions={revisions[0].reactions}
-
          timestamp={revisions[0].timestamp}
-
          body={revisions[0].description.slice(-1)[0].body}
-
          reactOnComment={partial(
-
            reactOnRevision,
-
            config.publicKey,
-
            revisions[0].id,
-
          )}
-
          editComment={roles.isDelegateOrAuthor(
-
            config.publicKey,
-
            repo.delegates.map(delegate => delegate.did),
-
            revisions[0].author.did,
-
          ) && partial(editRevision, revisions[0].id)}>
-
        </CommentComponent>
-
      </div>
-

-
      <div>
-
        <!-- svelte-ignore a11y_click_events_have_key_events -->
-
        <div
-
          role="button"
-
          tabindex="0"
-
          class="txt-semibold global-flex"
-
          style:margin-bottom="1rem"
-
          style:cursor="pointer"
-
          onclick={() => (hideTimeline = !hideTimeline)}>
-
          <Icon
-
            name={hideTimeline ? "chevron-right" : "chevron-down"} />Timeline
+
      <Border
+
        variant="ghost"
+
        flatTop
+
        styleWidth="100%"
+
        stylePadding="1rem"
+
        styleDisplay="block"
+
        styleFlexDirection="column"
+
        styleAlignItems="flex-start">
+
        <div class="txt-small patch-body">
+
          <CommentComponent
+
            caption="opened"
+
            rid={repo.rid}
+
            id={patch.id}
+
            lastEdit={revisions[0].description.length > 1
+
              ? revisions[0].description.at(-1)
+
              : undefined}
+
            author={revisions[0].author}
+
            reactions={revisions[0].reactions}
+
            timestamp={revisions[0].timestamp}
+
            body={revisions[0].description.slice(-1)[0].body}
+
            reactOnComment={partial(
+
              reactOnRevision,
+
              config.publicKey,
+
              revisions[0].id,
+
            )}
+
            editComment={roles.isDelegateOrAuthor(
+
              config.publicKey,
+
              repo.delegates.map(delegate => delegate.did),
+
              revisions[0].author.did,
+
            ) && partial(editRevision, revisions[0].id)}>
+
          </CommentComponent>
        </div>
-
        <div class:hide-timeline={hideTimeline}>
-
          <PatchTimeline {activity} patchId={patch.id} />
+

+
        <Border variant="ghost" styleGap="0">
+
          <div class="metadata-section" style:min-width="8rem">
+
            <div class="metadata-section-title">Status</div>
+
            <PatchStateBadge state={patch.state} />
+
          </div>
+

+
          <div class="metadata-divider"></div>
+

+
          <div class="metadata-section" style:flex="1">
+
            <LabelInput
+
              allowedToEdit={!!roles.isDelegateOrAuthor(
+
                config.publicKey,
+
                repo.delegates.map(delegate => delegate.did),
+
                patch.author.did,
+
              )}
+
              labels={patch.labels}
+
              submitInProgress={labelSaveInProgress}
+
              save={saveLabels} />
+
          </div>
+

+
          <div class="metadata-divider"></div>
+

+
          <div class="metadata-section" style:flex="1">
+
            <AssigneeInput
+
              allowedToEdit={!!roles.isDelegateOrAuthor(
+
                config.publicKey,
+
                repo.delegates.map(delegate => delegate.did),
+
                patch.author.did,
+
              )}
+
              assignees={patch.assignees}
+
              submitInProgress={assigneesSaveInProgress}
+
              save={saveAssignees} />
+
          </div>
+
        </Border>
+

+
        <div>
+
          <!-- svelte-ignore a11y_click_events_have_key_events -->
+
          <div
+
            role="button"
+
            tabindex="0"
+
            class="txt-semibold global-flex"
+
            style:margin="1rem 0"
+
            style:cursor="pointer"
+
            onclick={() => (hideTimeline = !hideTimeline)}>
+
            <Icon
+
              name={hideTimeline ? "chevron-right" : "chevron-down"} />Timeline
+
          </div>
+
          <div class:hide-timeline={hideTimeline}>
+
            <PatchTimeline {activity} patchId={patch.id} />
+
          </div>
        </div>
-
      </div>
+
      </Border>
    {:else}
-
      {@const revision = revisions.slice(-1)[0]}
-
      {#await loadHighlightedDiff(repo.rid, revision.base, revision.head) then diff}
-
        <div style:margin-top="1rem">
+
      <Border
+
        variant="ghost"
+
        flatTop
+
        styleDisplay="block"
+
        stylePadding="1rem"
+
        styleAlignItems="flex-start">
+
        {@const revision = revisions.slice(-1)[0]}
+
        {#await loadHighlightedDiff(repo.rid, revision.base, revision.head) then diff}
          <Changeset {diff} repoId={repo.rid} />
-
        </div>
-
      {/await}
+
        {/await}
+
      </Border>
    {/if}
  </div>
</Layout>