Style patch tabs

This commit is contained in:
Rūdolfs Ošiņš
2025-01-16 12:31:46 -06:00
parent 6326863f21
commit 63ec8cb473
5 changed files with 235 additions and 105 deletions
+21 -1
View File
@@ -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}
+5 -1
View File
@@ -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}
+3 -2
View File
@@ -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;
+75
View File
@@ -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>
+131 -101
View File
@@ -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="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>
<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>
<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>
<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>
<!-- 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" 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 class:hide-timeline={hideTimeline}>
<PatchTimeline {activity} patchId={patch.id} />
</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>