mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-12 02:30:35 +08:00
Extract buttons into own components
This commit is contained in:
committed by
Sebastian Martinez
parent
ace802118e
commit
7d977f22da
@@ -0,0 +1,48 @@
|
||||
<script lang="ts">
|
||||
import { formatOid } from "@app/lib/utils";
|
||||
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import Button from "@app/components/Button.svelte";
|
||||
import Command from "@app/components/Command.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import Popover from "@app/components/Popover.svelte";
|
||||
|
||||
interface Props {
|
||||
patchId: string;
|
||||
selectedRevisionId: string;
|
||||
tab: "patch" | "revisions" | "timeline";
|
||||
}
|
||||
|
||||
const { patchId, selectedRevisionId, tab }: Props = $props();
|
||||
|
||||
const checkoutCommand = $derived.by(() => {
|
||||
if (tab === "revisions" && selectedRevisionId !== patchId) {
|
||||
return `rad patch checkout ${formatOid(patchId)} --revision ${formatOid(selectedRevisionId)}`;
|
||||
} else {
|
||||
return `rad patch checkout ${formatOid(patchId)}`;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<Popover popoverPositionRight="0" popoverPositionTop="3rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<Button styleHeight="2.5rem" variant="secondary" {onclick}>
|
||||
<Icon name="checkout" />Checkout patch<Icon name="chevron-down" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
{#snippet popover()}
|
||||
<Border
|
||||
styleAlignItems="flex-start"
|
||||
styleBackgroundColor="var(--color-background-float)"
|
||||
styleFlexDirection="column"
|
||||
styleGap="0.5rem"
|
||||
stylePadding="1rem"
|
||||
styleWidth="max-content"
|
||||
variant="ghost">
|
||||
<span class="txt-small">
|
||||
To checkout this patch in your working copy, run:
|
||||
</span>
|
||||
<Command command={checkoutCommand} styleWidth="100%" />
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
@@ -0,0 +1,37 @@
|
||||
<script lang="ts">
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import Button from "@app/components/Button.svelte";
|
||||
import Command from "@app/components/Command.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import Popover from "@app/components/Popover.svelte";
|
||||
|
||||
interface Props {
|
||||
rid: string;
|
||||
}
|
||||
|
||||
const { rid }: Props = $props();
|
||||
</script>
|
||||
|
||||
<Popover popoverPositionRight="0" popoverPositionTop="3rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<Button styleHeight="2.5rem" variant="secondary" {onclick}>
|
||||
<Icon name="checkout" />Checkout repo<Icon name="chevron-down" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
|
||||
{#snippet popover()}
|
||||
<Border
|
||||
styleAlignItems="flex-start"
|
||||
styleBackgroundColor="var(--color-background-float)"
|
||||
styleFlexDirection="column"
|
||||
styleGap="0.5rem"
|
||||
stylePadding="1rem"
|
||||
styleWidth="max-content"
|
||||
variant="ghost">
|
||||
<span class="txt-small">
|
||||
To checkout a working copy of this repo, run:
|
||||
</span>
|
||||
<Command command={`rad checkout ${rid}`} styleWidth="100%" />
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="cmd txt-monospace" style:width={styleWidth}>
|
||||
<div class="cmd txt-monospace txt-small" style:width={styleWidth}>
|
||||
<Border
|
||||
hoverable
|
||||
onclick={() => clipboard.copy()}
|
||||
|
||||
@@ -1,29 +1,21 @@
|
||||
<script lang="ts">
|
||||
import type { Snippet } from "svelte";
|
||||
import type { Config } from "@bindings/config/Config";
|
||||
import type { Snippet } from "svelte";
|
||||
|
||||
import { boolean } from "zod";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
import * as router from "@app/lib/router";
|
||||
import useLocalStorage from "@app/lib/useLocalStorage.svelte";
|
||||
import {
|
||||
checkRadicleCLI,
|
||||
radicleInstalled,
|
||||
} from "@app/lib/checkRadicleCLI.svelte";
|
||||
import { checkRadicleCLI } from "@app/lib/checkRadicleCLI.svelte";
|
||||
import { dynamicInterval } from "@app/lib/interval";
|
||||
import { nodeRunning } from "@app/lib/events";
|
||||
import { didFromPublicKey, truncateDid } from "@app/lib/utils";
|
||||
import { setFocused } from "@app/components/Popover.svelte";
|
||||
|
||||
import Avatar from "@app/components/Avatar.svelte";
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import Command from "@app/components/Command.svelte";
|
||||
import CopyableId from "@app/components/CopyableId.svelte";
|
||||
import Repos from "@app/views/home/guides/Repos.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import InfoButton from "@app/components/InfoButton.svelte";
|
||||
import NakedButton from "@app/components/NakedButton.svelte";
|
||||
import NodeId from "@app/components/NodeId.svelte";
|
||||
import Popover, { setFocused } from "@app/components/Popover.svelte";
|
||||
import NodeStatusButton from "@app/components/NodeStatusButton.svelte";
|
||||
|
||||
const activeRouteStore = router.activeRouteStore;
|
||||
|
||||
@@ -39,6 +31,8 @@
|
||||
center?: Snippet;
|
||||
}
|
||||
|
||||
const { center, config }: Props = $props();
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
await checkRadicleCLI();
|
||||
@@ -52,8 +46,6 @@
|
||||
firstLaunchStorage.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
const { center, config }: Props = $props();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -85,15 +77,6 @@
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.guide-header {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.spacer {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid var(--color-border-default);
|
||||
height: 1px;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="header global-flex">
|
||||
@@ -129,122 +112,8 @@
|
||||
{@render center?.()}
|
||||
|
||||
<div class="global-flex">
|
||||
<Popover
|
||||
popoverId="popover-guide"
|
||||
popoverPadding="0"
|
||||
popoverPositionTop="2.5rem"
|
||||
popoverPositionRight="-9.3rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<NakedButton variant="ghost" {onclick} stylePadding="0 4px">
|
||||
<Icon name="info" />
|
||||
</NakedButton>
|
||||
{/snippet}
|
||||
{#snippet popover()}
|
||||
<Border
|
||||
variant="ghost"
|
||||
styleGap="0"
|
||||
stylePadding="1rem"
|
||||
styleMinWidth="36rem"
|
||||
styleOverflow="auto"
|
||||
styleMaxHeight="calc(100vh - 5rem)"
|
||||
styleAlignItems="flex-start"
|
||||
styleFlexDirection="column">
|
||||
<div
|
||||
style:position="relative"
|
||||
style:display="flex"
|
||||
style:gap="0.5rem"
|
||||
style:flex-direction="column"
|
||||
style:padding="1rem"
|
||||
style:margin-bottom="1rem"
|
||||
style:width="100%"
|
||||
style:background-color="var(--color-background-float)">
|
||||
<div class="txt-semibold txt-medium" style:margin-bottom="1rem">
|
||||
Getting started
|
||||
</div>
|
||||
<div class="txt-small" style:display="inline">
|
||||
Hello <span style:padding-left="0.25rem">
|
||||
<NodeId
|
||||
inline
|
||||
publicKey={config.publicKey}
|
||||
alias={config.alias} />,
|
||||
</span>
|
||||
your identity has been created and stored on your machine.
|
||||
</div>
|
||||
<div class="txt-small">
|
||||
Your public key is <CopyableId
|
||||
inline
|
||||
id={didFromPublicKey(config.publicKey)}>
|
||||
{truncateDid(config.publicKey)}
|
||||
</CopyableId>
|
||||
you can share this with anyone to find you on the network.
|
||||
</div>
|
||||
<div class="spacer"></div>
|
||||
{#if radicleInstalled()}
|
||||
<div class="global-flex txt-small">
|
||||
<Icon name="checkbox-checked" />Radicle CLI is setup
|
||||
</div>
|
||||
{:else}
|
||||
<div class="txt-small">
|
||||
<div class="global-flex" style:padding-bottom="0.5rem">
|
||||
<Icon name="checkbox-unchecked" />Make sure to install
|
||||
Radicle CLI
|
||||
</div>
|
||||
<div style:padding-bottom="0.5rem">
|
||||
To be able to interact with repos on the Radicle network
|
||||
you'll need to install a node on your computer. This node
|
||||
will identify itself on the network with your keys to push
|
||||
and pull changes.
|
||||
</div>
|
||||
<div style:padding-bottom="0.5rem">
|
||||
To install the node and other Radicle CLI tooling, simply
|
||||
run the command below from your shell:
|
||||
</div>
|
||||
<Command
|
||||
styleWidth="fit-content"
|
||||
command="curl -sSf https://radicle.xyz/install | sh" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="guide-header txt-medium txt-semibold">Guide</div>
|
||||
|
||||
<Repos />
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
<Popover
|
||||
popoverPadding="0"
|
||||
popoverPositionTop="2.5rem"
|
||||
popoverPositionRight="0">
|
||||
{#snippet toggle(onclick)}
|
||||
<NakedButton variant="ghost" {onclick}>
|
||||
{#if $nodeRunning}
|
||||
<Icon name="online" />
|
||||
Online
|
||||
{:else}
|
||||
<Icon name="offline" />
|
||||
Offline
|
||||
{/if}
|
||||
</NakedButton>
|
||||
{/snippet}
|
||||
{#snippet popover()}
|
||||
<Border
|
||||
variant="ghost"
|
||||
stylePadding="1rem"
|
||||
styleMinWidth="20rem"
|
||||
styleAlignItems="flex-start"
|
||||
styleFlexDirection="column">
|
||||
<div class="txt-small txt-missing">
|
||||
{#if $nodeRunning}
|
||||
Your node is up and running, your changes will be synced
|
||||
automatically.
|
||||
{:else}
|
||||
Your node is not running, changes you make are safe but won't
|
||||
be announced.
|
||||
{/if}
|
||||
</div>
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
<InfoButton {config} />
|
||||
<NodeStatusButton />
|
||||
<NakedButton
|
||||
variant="ghost"
|
||||
stylePadding="0 4px"
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<script lang="ts">
|
||||
import type { Config } from "@bindings/config/Config";
|
||||
|
||||
import { didFromPublicKey, truncateDid } from "@app/lib/utils";
|
||||
import { radicleInstalled } from "@app/lib/checkRadicleCLI.svelte";
|
||||
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import Command from "@app/components/Command.svelte";
|
||||
import CopyableId from "@app/components/CopyableId.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import NakedButton from "@app/components/NakedButton.svelte";
|
||||
import NodeId from "@app/components/NodeId.svelte";
|
||||
import Popover from "@app/components/Popover.svelte";
|
||||
import RepoGuide from "@app/components/RepoGuide.svelte";
|
||||
|
||||
interface Props {
|
||||
config: Config;
|
||||
}
|
||||
const { config }: Props = $props();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.guide-header {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.spacer {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid var(--color-border-default);
|
||||
height: 1px;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<Popover
|
||||
popoverId="popover-guide"
|
||||
popoverPadding="0"
|
||||
popoverPositionTop="2.5rem"
|
||||
popoverPositionRight="-9.3rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<NakedButton variant="ghost" {onclick} stylePadding="0 4px">
|
||||
<Icon name="info" />
|
||||
</NakedButton>
|
||||
{/snippet}
|
||||
{#snippet popover()}
|
||||
<Border
|
||||
variant="ghost"
|
||||
styleGap="0"
|
||||
stylePadding="1rem"
|
||||
styleMinWidth="36rem"
|
||||
styleOverflow="auto"
|
||||
styleMaxHeight="calc(100vh - 5rem)"
|
||||
styleAlignItems="flex-start"
|
||||
styleFlexDirection="column">
|
||||
<div
|
||||
style:position="relative"
|
||||
style:display="flex"
|
||||
style:gap="0.5rem"
|
||||
style:flex-direction="column"
|
||||
style:padding="1rem"
|
||||
style:margin-bottom="1rem"
|
||||
style:width="100%"
|
||||
style:background-color="var(--color-background-float)">
|
||||
<div class="txt-semibold txt-medium" style:margin-bottom="1rem">
|
||||
Getting started
|
||||
</div>
|
||||
<div class="txt-small" style:display="inline">
|
||||
Hello <span style:padding-left="0.25rem">
|
||||
<NodeId inline publicKey={config.publicKey} alias={config.alias} />,
|
||||
</span>
|
||||
your identity has been created and stored on your machine.
|
||||
</div>
|
||||
<div class="txt-small">
|
||||
Your public key is <CopyableId
|
||||
inline
|
||||
id={didFromPublicKey(config.publicKey)}>
|
||||
{truncateDid(config.publicKey)}
|
||||
</CopyableId>
|
||||
you can share this with anyone to find you on the network.
|
||||
</div>
|
||||
<div class="spacer"></div>
|
||||
{#if radicleInstalled()}
|
||||
<div class="global-flex txt-small">
|
||||
<Icon name="checkbox-checked" />Radicle CLI is setup
|
||||
</div>
|
||||
{:else}
|
||||
<div class="txt-small">
|
||||
<div class="global-flex" style:padding-bottom="0.5rem">
|
||||
<Icon name="checkbox-unchecked" />Make sure to install Radicle CLI
|
||||
</div>
|
||||
<div style:padding-bottom="0.5rem">
|
||||
To be able to interact with repos on the Radicle network you'll
|
||||
need to install a node on your computer. This node will identify
|
||||
itself on the network with your keys to push and pull changes.
|
||||
</div>
|
||||
<div style:padding-bottom="0.5rem">
|
||||
To install the node and other Radicle CLI tooling, simply run the
|
||||
command below from your shell:
|
||||
</div>
|
||||
<Command
|
||||
styleWidth="fit-content"
|
||||
command="curl -sSf https://radicle.xyz/install | sh" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="guide-header txt-medium txt-semibold">Guide</div>
|
||||
|
||||
<RepoGuide />
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
@@ -1,40 +1,35 @@
|
||||
<script lang="ts">
|
||||
import type { Issue } from "@bindings/cob/issue/Issue";
|
||||
import type { RepoInfo } from "@bindings/repo/RepoInfo";
|
||||
import type { IssueStatus } from "@app/views/repo/router";
|
||||
import type { RepoInfo } from "@bindings/repo/RepoInfo";
|
||||
|
||||
import capitalize from "lodash/capitalize";
|
||||
import fuzzysort from "fuzzysort";
|
||||
|
||||
import * as router from "@app/lib/router";
|
||||
import { issueStatusColor, modifierKey } from "@app/lib/utils";
|
||||
import { modifierKey } from "@app/lib/utils";
|
||||
|
||||
import Border from "./Border.svelte";
|
||||
import DropdownList from "./DropdownList.svelte";
|
||||
import DropdownListItem from "./DropdownListItem.svelte";
|
||||
import Icon from "./Icon.svelte";
|
||||
import IssueStateFilterButton from "./IssueStateFilterButton.svelte";
|
||||
import IssueTeaser from "@app/components/IssueTeaser.svelte";
|
||||
import Link from "./Link.svelte";
|
||||
import NakedButton from "./NakedButton.svelte";
|
||||
import OutlineButton from "./OutlineButton.svelte";
|
||||
import Popover, { closeFocused } from "./Popover.svelte";
|
||||
import TextInput from "./TextInput.svelte";
|
||||
|
||||
const activeRouteStore = router.activeRouteStore;
|
||||
|
||||
interface Props {
|
||||
changeFilter: (status: IssueStatus) => void;
|
||||
issues: Issue[];
|
||||
repo: RepoInfo;
|
||||
selectedIssueId?: string;
|
||||
issues: Issue[];
|
||||
status: IssueStatus;
|
||||
title: string;
|
||||
changeFilter: (status: IssueStatus) => void;
|
||||
}
|
||||
|
||||
/* eslint-disable prefer-const */
|
||||
let { repo, selectedIssueId, issues, status, title, changeFilter }: Props =
|
||||
const { changeFilter, issues, repo, selectedIssueId, status, title }: Props =
|
||||
$props();
|
||||
/* eslint-enable prefer-const */
|
||||
|
||||
const project = $derived(repo.payloads["xyz.radicle.project"]!);
|
||||
|
||||
@@ -81,24 +76,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
{#snippet icons(status: IssueStatus)}
|
||||
<div
|
||||
class="icon"
|
||||
style:color={status === "all" ? undefined : issueStatusColor[status]}>
|
||||
<Icon name={status === "closed" ? "issue-closed" : "issue"} />
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
{#snippet counters(status: IssueStatus)}
|
||||
<div style:margin-left="auto" style:padding-left="0.25rem">
|
||||
{#if status === "all"}
|
||||
{project.meta.issues.open + project.meta.issues.closed}
|
||||
{:else}
|
||||
{project.meta.issues[status]}
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<div class="container">
|
||||
<div
|
||||
class="txt-medium global-flex"
|
||||
@@ -157,37 +134,10 @@
|
||||
|
||||
{#if showFilters}
|
||||
<div class="global-flex" style:margin="1rem 0">
|
||||
<Popover popoverPositionLeft="0" popoverPositionTop="3rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<OutlineButton variant="ghost" {onclick} styleHeight="2.5rem">
|
||||
{@render icons(status)}
|
||||
{capitalize(status)}
|
||||
{@render counters(status)}
|
||||
<Icon name="chevron-down" />
|
||||
</OutlineButton>
|
||||
{/snippet}
|
||||
|
||||
{#snippet popover()}
|
||||
<Border variant="ghost">
|
||||
<DropdownList items={["all", "open", "closed"] as IssueStatus[]}>
|
||||
{#snippet item(state)}
|
||||
<DropdownListItem
|
||||
styleGap="0.5rem"
|
||||
styleMinHeight="2.5rem"
|
||||
selected={status === state}
|
||||
onclick={() => {
|
||||
changeFilter(state);
|
||||
closeFocused();
|
||||
}}>
|
||||
{@render icons(state)}
|
||||
{capitalize(state)}
|
||||
{@render counters(state)}
|
||||
</DropdownListItem>
|
||||
{/snippet}
|
||||
</DropdownList>
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
<IssueStateFilterButton
|
||||
{status}
|
||||
counters={project.meta.issues}
|
||||
{changeFilter} />
|
||||
<TextInput
|
||||
onSubmit={async () => {
|
||||
if (searchResults.length === 1) {
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<script lang="ts">
|
||||
import type { IssueStatus } from "@app/views/repo/router";
|
||||
import type { ProjectPayloadMeta } from "@bindings/repo/ProjectPayloadMeta";
|
||||
|
||||
import { closeFocused } from "./Popover.svelte";
|
||||
|
||||
import capitalize from "lodash/capitalize";
|
||||
import { issueStatusColor } from "@app/lib/utils";
|
||||
|
||||
import Border from "./Border.svelte";
|
||||
import DropdownList from "./DropdownList.svelte";
|
||||
import DropdownListItem from "./DropdownListItem.svelte";
|
||||
import Icon from "./Icon.svelte";
|
||||
import OutlineButton from "./OutlineButton.svelte";
|
||||
import Popover from "./Popover.svelte";
|
||||
|
||||
interface Props {
|
||||
changeFilter: (status: IssueStatus) => void;
|
||||
status: IssueStatus;
|
||||
counters: ProjectPayloadMeta["issues"];
|
||||
}
|
||||
|
||||
const { changeFilter, counters, status }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#snippet iconSnippet(status: IssueStatus)}
|
||||
<div
|
||||
class="icon"
|
||||
style:color={status === "all" ? undefined : issueStatusColor[status]}>
|
||||
<Icon name={status === "closed" ? "issue-closed" : "issue"} />
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
{#snippet counterSnippet(status: IssueStatus)}
|
||||
<div style:margin-left="auto" style:padding-left="0.25rem">
|
||||
{#if status === "all"}
|
||||
{counters.open + counters.closed}
|
||||
{:else}
|
||||
{counters[status]}
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<Popover popoverPositionLeft="0" popoverPositionTop="3rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<OutlineButton variant="ghost" {onclick} styleHeight="2.5rem">
|
||||
{@render iconSnippet(status)}
|
||||
{capitalize(status)}
|
||||
{@render counterSnippet(status)}
|
||||
<Icon name="chevron-down" />
|
||||
</OutlineButton>
|
||||
{/snippet}
|
||||
|
||||
{#snippet popover()}
|
||||
<Border variant="ghost">
|
||||
<DropdownList items={["all", "open", "closed"] as IssueStatus[]}>
|
||||
{#snippet item(state)}
|
||||
<DropdownListItem
|
||||
styleGap="0.5rem"
|
||||
styleMinHeight="2.5rem"
|
||||
selected={status === state}
|
||||
onclick={() => {
|
||||
changeFilter(state);
|
||||
closeFocused();
|
||||
}}>
|
||||
{@render iconSnippet(state)}
|
||||
{capitalize(state)}
|
||||
{@render counterSnippet(state)}
|
||||
</DropdownListItem>
|
||||
{/snippet}
|
||||
</DropdownList>
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
@@ -0,0 +1,43 @@
|
||||
<script lang="ts">
|
||||
import { nodeRunning } from "@app/lib/events";
|
||||
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import NakedButton from "@app/components/NakedButton.svelte";
|
||||
import Popover from "@app/components/Popover.svelte";
|
||||
</script>
|
||||
|
||||
<Popover
|
||||
popoverPadding="0"
|
||||
popoverPositionTop="2.5rem"
|
||||
popoverPositionRight="0">
|
||||
{#snippet toggle(onclick)}
|
||||
<NakedButton variant="ghost" {onclick}>
|
||||
{#if $nodeRunning}
|
||||
<Icon name="online" />
|
||||
Online
|
||||
{:else}
|
||||
<Icon name="offline" />
|
||||
Offline
|
||||
{/if}
|
||||
</NakedButton>
|
||||
{/snippet}
|
||||
{#snippet popover()}
|
||||
<Border
|
||||
variant="ghost"
|
||||
stylePadding="1rem"
|
||||
styleMinWidth="20rem"
|
||||
styleAlignItems="flex-start"
|
||||
styleFlexDirection="column">
|
||||
<div class="txt-small txt-missing">
|
||||
{#if $nodeRunning}
|
||||
Your node is up and running, your changes will be synced
|
||||
automatically.
|
||||
{:else}
|
||||
Your node is not running, changes you make are safe but won't be
|
||||
announced.
|
||||
{/if}
|
||||
</div>
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
@@ -0,0 +1,77 @@
|
||||
<script lang="ts">
|
||||
import type { PatchStatus } from "@app/views/repo/router";
|
||||
import type { ProjectPayloadMeta } from "@bindings/repo/ProjectPayloadMeta";
|
||||
|
||||
import capitalize from "lodash/capitalize";
|
||||
|
||||
import { patchStatusColor } from "@app/lib/utils";
|
||||
|
||||
import { closeFocused } from "@app/components/Popover.svelte";
|
||||
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import DropdownList from "@app/components/DropdownList.svelte";
|
||||
import DropdownListItem from "@app/components/DropdownListItem.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import OutlineButton from "@app/components/OutlineButton.svelte";
|
||||
import Popover from "@app/components/Popover.svelte";
|
||||
|
||||
interface Props {
|
||||
counters: ProjectPayloadMeta["patches"];
|
||||
select: (filter: PatchStatus | undefined) => Promise<void>;
|
||||
status: PatchStatus | undefined;
|
||||
}
|
||||
|
||||
const { status, select, counters }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#snippet iconSnippet(status: PatchStatus | undefined)}
|
||||
<div class="icon" style:color={status ? patchStatusColor[status] : undefined}>
|
||||
<Icon
|
||||
name={status === undefined || status === "open"
|
||||
? "patch"
|
||||
: `patch-${status}`} />
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
{#snippet counterSnippet(status: PatchStatus | undefined)}
|
||||
<div style:margin-left="auto" style:padding-left="0.25rem">
|
||||
{#if status}
|
||||
{counters[status]}
|
||||
{:else}
|
||||
{counters.draft + counters.open + counters.archived + counters.merged}
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<Popover popoverPositionLeft="0" popoverPositionTop="3rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<OutlineButton variant="ghost" {onclick} styleHeight="2.5rem">
|
||||
{@render iconSnippet(status)}
|
||||
{status ? capitalize(status) : "All"}
|
||||
{@render counterSnippet(status)}
|
||||
<Icon name="chevron-down" />
|
||||
</OutlineButton>
|
||||
{/snippet}
|
||||
|
||||
{#snippet popover()}
|
||||
<Border variant="ghost">
|
||||
<DropdownList
|
||||
items={[undefined, "draft", "open", "archived", "merged"] as const}>
|
||||
{#snippet item(state)}
|
||||
<DropdownListItem
|
||||
styleGap="0.5rem"
|
||||
styleMinHeight="2.5rem"
|
||||
selected={status === state}
|
||||
onclick={async () => {
|
||||
await select(state);
|
||||
closeFocused();
|
||||
}}>
|
||||
{@render iconSnippet(state)}
|
||||
{state ? capitalize(state) : "All"}
|
||||
{@render counterSnippet(state)}
|
||||
</DropdownListItem>
|
||||
{/snippet}
|
||||
</DropdownList>
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
@@ -1,12 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { z } from "zod";
|
||||
import publish from "@app/views/home/publish.md?raw";
|
||||
import clone from "@app/views/home/clone.md?raw";
|
||||
|
||||
import useLocalStorage from "@app/lib/useLocalStorage.svelte";
|
||||
|
||||
import clone from "@app/components/RepoGuide/clone.md?raw";
|
||||
import publish from "@app/components/RepoGuide/publish.md?raw";
|
||||
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import Markdown from "@app/components/Markdown.svelte";
|
||||
import Tab from "@app/components/Tab.svelte";
|
||||
import useLocalStorage from "@app/lib/useLocalStorage.svelte";
|
||||
|
||||
const tab = useLocalStorage(
|
||||
"repoGuideTab",
|
||||
@@ -0,0 +1,136 @@
|
||||
<script lang="ts">
|
||||
import type { Config } from "@bindings/config/Config";
|
||||
import type { PatchStatus } from "@app/views/repo/router";
|
||||
import type { Review } from "@bindings/cob/patch/Review";
|
||||
import type { Revision } from "@bindings/cob/patch/Revision";
|
||||
import type { Verdict } from "@bindings/cob/patch/Verdict";
|
||||
|
||||
import { closeFocused } from "./Popover.svelte";
|
||||
import { didFromPublicKey } from "@app/lib/utils";
|
||||
import { push } from "@app/lib/router";
|
||||
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import NakedButton from "@app/components/NakedButton.svelte";
|
||||
import OutlineButton from "@app/components/OutlineButton.svelte";
|
||||
import Popover from "@app/components/Popover.svelte";
|
||||
|
||||
interface Props {
|
||||
rid: string;
|
||||
patchId: string;
|
||||
revision: Revision;
|
||||
config: Config;
|
||||
status: PatchStatus | undefined;
|
||||
loadPatch: () => Promise<void>;
|
||||
createReview: (verdict?: Verdict) => Promise<Review | undefined>;
|
||||
}
|
||||
|
||||
const {
|
||||
rid,
|
||||
patchId,
|
||||
revision,
|
||||
config,
|
||||
status,
|
||||
loadPatch,
|
||||
createReview,
|
||||
}: Props = $props();
|
||||
|
||||
const hasOwnReview = $derived(
|
||||
Boolean(
|
||||
revision.reviews &&
|
||||
revision.reviews.some(
|
||||
value => value.author.did === didFromPublicKey(config.publicKey),
|
||||
),
|
||||
),
|
||||
);
|
||||
</script>
|
||||
|
||||
<Popover popoverPositionRight="0" popoverPositionTop="2.5rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<NakedButton
|
||||
variant="ghost"
|
||||
disabled={hasOwnReview}
|
||||
{onclick}
|
||||
title={hasOwnReview ? "You already published a review" : undefined}>
|
||||
<Icon name="add" />
|
||||
<span class="txt-small">Review</span>
|
||||
</NakedButton>
|
||||
{/snippet}
|
||||
|
||||
{#snippet popover()}
|
||||
<Border
|
||||
variant="ghost"
|
||||
stylePadding="1rem"
|
||||
styleDisplay="flex"
|
||||
styleFlexDirection="column">
|
||||
<div class="global-flex">
|
||||
<OutlineButton
|
||||
variant="ghost"
|
||||
disabled={hasOwnReview}
|
||||
title={hasOwnReview ? "You already published a review" : undefined}
|
||||
onclick={async () => {
|
||||
const newReview = await createReview();
|
||||
if (newReview) {
|
||||
await push({
|
||||
resource: "repo.patch",
|
||||
rid,
|
||||
patch: patchId,
|
||||
status,
|
||||
reviewId: newReview.id,
|
||||
});
|
||||
}
|
||||
closeFocused();
|
||||
}}>
|
||||
<span class="global-flex" style:color="var(--color-foreground-dim)">
|
||||
<Icon name="comment" />
|
||||
<span class="txt-small">Write Review</span>
|
||||
</span>
|
||||
</OutlineButton>
|
||||
<OutlineButton
|
||||
variant="ghost"
|
||||
disabled={hasOwnReview}
|
||||
title={hasOwnReview ? "You already published a review" : undefined}
|
||||
onclick={async () => {
|
||||
await createReview("reject");
|
||||
await loadPatch();
|
||||
closeFocused();
|
||||
}}>
|
||||
<span class="global-flex" style:color="var(--color-foreground-red)">
|
||||
<Icon name="comment-cross" />
|
||||
<span class="txt-small">Reject</span>
|
||||
</span>
|
||||
</OutlineButton>
|
||||
<OutlineButton
|
||||
variant="ghost"
|
||||
disabled={hasOwnReview}
|
||||
title={hasOwnReview ? "You already published a review" : undefined}
|
||||
onclick={async () => {
|
||||
await createReview("accept");
|
||||
await loadPatch();
|
||||
closeFocused();
|
||||
}}>
|
||||
<span
|
||||
class="global-flex"
|
||||
style:color="var(--color-foreground-success)">
|
||||
<Icon name="comment-checkmark" />
|
||||
<span class="txt-small">Accept</span>
|
||||
<span></span>
|
||||
</span>
|
||||
</OutlineButton>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="txt-small txt-missing global-flex"
|
||||
style:margin-top="0.5rem"
|
||||
style:align-items="flex-start">
|
||||
<div style:padding-top="3px"><Icon name="info" /></div>
|
||||
<div>
|
||||
Clicking the buttons will create a blank review, add comments, a
|
||||
summary, and your verdict after. Depending on your sync settings your
|
||||
review might be published to the network right away. We are actively
|
||||
working on draft reviews, stay tuned.
|
||||
</div>
|
||||
</div>
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
+13
-118
@@ -6,43 +6,29 @@
|
||||
import type { Verdict } from "@bindings/cob/patch/Verdict";
|
||||
|
||||
import { announce } from "@app/components/AnnounceSwitch.svelte";
|
||||
import { closeFocused } from "./Popover.svelte";
|
||||
import { didFromPublicKey } from "@app/lib/utils";
|
||||
import { invoke } from "@app/lib/invoke";
|
||||
import { nodeRunning } from "@app/lib/events";
|
||||
import { push } from "@app/lib/router";
|
||||
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import NakedButton from "@app/components/NakedButton.svelte";
|
||||
import OutlineButton from "@app/components/OutlineButton.svelte";
|
||||
import Popover from "@app/components/Popover.svelte";
|
||||
import ReviewButton from "@app/components/ReviewButton.svelte";
|
||||
import ReviewTeaser from "@app/components/ReviewTeaser.svelte";
|
||||
|
||||
interface Props {
|
||||
rid: string;
|
||||
config: Config;
|
||||
loadPatch: () => Promise<void>;
|
||||
patchId: string;
|
||||
revision: Revision;
|
||||
config: Config;
|
||||
rid: string;
|
||||
status: PatchStatus | undefined;
|
||||
loadPatch: () => Promise<void>;
|
||||
}
|
||||
|
||||
const { rid, patchId, revision, config, status, loadPatch }: Props = $props();
|
||||
const { config, loadPatch, patchId, revision, rid, status }: Props = $props();
|
||||
|
||||
let hideReviews = $state(
|
||||
revision.reviews === undefined || revision.reviews.length === 0,
|
||||
);
|
||||
|
||||
const hasOwnReview = $derived(
|
||||
Boolean(
|
||||
revision.reviews &&
|
||||
revision.reviews.some(
|
||||
value => value.author.did === didFromPublicKey(config.publicKey),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$effect(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
patchId;
|
||||
@@ -96,105 +82,14 @@
|
||||
</NakedButton>
|
||||
|
||||
<div class="global-flex" style:margin-left="auto">
|
||||
<Popover popoverPositionRight="0" popoverPositionTop="2.5rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<NakedButton
|
||||
variant="ghost"
|
||||
disabled={hasOwnReview}
|
||||
{onclick}
|
||||
title={hasOwnReview ? "You already published a review" : undefined}>
|
||||
<Icon name="add" />
|
||||
<span class="txt-small">Review</span>
|
||||
</NakedButton>
|
||||
{/snippet}
|
||||
|
||||
{#snippet popover()}
|
||||
<Border
|
||||
variant="ghost"
|
||||
stylePadding="1rem"
|
||||
styleDisplay="flex"
|
||||
styleFlexDirection="column">
|
||||
<div class="global-flex">
|
||||
<OutlineButton
|
||||
variant="ghost"
|
||||
disabled={hasOwnReview}
|
||||
title={hasOwnReview
|
||||
? "You already published a review"
|
||||
: undefined}
|
||||
onclick={async () => {
|
||||
const newReview = await createReview();
|
||||
if (newReview) {
|
||||
await push({
|
||||
resource: "repo.patch",
|
||||
rid,
|
||||
patch: patchId,
|
||||
status,
|
||||
reviewId: newReview.id,
|
||||
});
|
||||
}
|
||||
closeFocused();
|
||||
}}>
|
||||
<span
|
||||
class="global-flex"
|
||||
style:color="var(--color-foreground-dim)">
|
||||
<Icon name="comment" />
|
||||
<span class="txt-small">Write Review</span>
|
||||
</span>
|
||||
</OutlineButton>
|
||||
<OutlineButton
|
||||
variant="ghost"
|
||||
disabled={hasOwnReview}
|
||||
title={hasOwnReview
|
||||
? "You already published a review"
|
||||
: undefined}
|
||||
onclick={async () => {
|
||||
await createReview("reject");
|
||||
await loadPatch();
|
||||
closeFocused();
|
||||
}}>
|
||||
<span
|
||||
class="global-flex"
|
||||
style:color="var(--color-foreground-red)">
|
||||
<Icon name="comment-cross" />
|
||||
<span class="txt-small">Reject</span>
|
||||
</span>
|
||||
</OutlineButton>
|
||||
<OutlineButton
|
||||
variant="ghost"
|
||||
disabled={hasOwnReview}
|
||||
title={hasOwnReview
|
||||
? "You already published a review"
|
||||
: undefined}
|
||||
onclick={async () => {
|
||||
await createReview("accept");
|
||||
await loadPatch();
|
||||
closeFocused();
|
||||
}}>
|
||||
<span
|
||||
class="global-flex"
|
||||
style:color="var(--color-foreground-success)">
|
||||
<Icon name="comment-checkmark" />
|
||||
<span class="txt-small">Accept</span>
|
||||
<span></span>
|
||||
</span>
|
||||
</OutlineButton>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="txt-small txt-missing global-flex"
|
||||
style:margin-top="0.5rem"
|
||||
style:align-items="flex-start">
|
||||
<div style:padding-top="3px"><Icon name="info" /></div>
|
||||
<div>
|
||||
Clicking the buttons will create a blank review, add comments, a
|
||||
summary, and your verdict after. Depending on your sync settings
|
||||
your review might be published to the network right away. We are
|
||||
actively working on draft reviews, stay tuned.
|
||||
</div>
|
||||
</div>
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
<ReviewButton
|
||||
{rid}
|
||||
{patchId}
|
||||
{revision}
|
||||
{config}
|
||||
{status}
|
||||
{loadPatch}
|
||||
{createReview} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
+13
-96
@@ -10,7 +10,6 @@
|
||||
import type { Review } from "@bindings/cob/patch/Review";
|
||||
import type { Revision } from "@bindings/cob/patch/Revision";
|
||||
|
||||
import capitalize from "lodash/capitalize";
|
||||
import fuzzysort from "fuzzysort";
|
||||
|
||||
import * as roles from "@app/lib/roles";
|
||||
@@ -28,11 +27,8 @@
|
||||
|
||||
import AssigneeInput from "@app/components/AssigneeInput.svelte";
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import Button from "@app/components/Button.svelte";
|
||||
import Command from "@app/components/Command.svelte";
|
||||
import CheckoutPatchButton from "@app/components/CheckoutPatchButton.svelte";
|
||||
import CopyableId from "@app/components/CopyableId.svelte";
|
||||
import DropdownList from "@app/components/DropdownList.svelte";
|
||||
import DropdownListItem from "@app/components/DropdownListItem.svelte";
|
||||
import EditableTitle from "@app/components/EditableTitle.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import LabelInput from "@app/components/LabelInput.svelte";
|
||||
@@ -40,11 +36,10 @@
|
||||
import Link from "@app/components/Link.svelte";
|
||||
import NakedButton from "@app/components/NakedButton.svelte";
|
||||
import NewPatchButton from "@app/components/NewPatchButton.svelte";
|
||||
import OutlineButton from "@app/components/OutlineButton.svelte";
|
||||
import PatchStateButton from "@app/components/PatchStateButton.svelte";
|
||||
import PatchStateFilterButton from "@app/components/PatchStateFilterButton.svelte";
|
||||
import PatchTeaser from "@app/components/PatchTeaser.svelte";
|
||||
import PatchTimeline from "@app/components/PatchTimeline.svelte";
|
||||
import Popover, { closeFocused } from "@app/components/Popover.svelte";
|
||||
import ReviewComponent from "@app/components/Review.svelte";
|
||||
import RevisionBadges from "@app/components/RevisionBadges.svelte";
|
||||
import RevisionComponent from "@app/components/Revision.svelte";
|
||||
@@ -104,13 +99,6 @@
|
||||
more = patches.more;
|
||||
});
|
||||
|
||||
const checkoutCommand = $derived.by(() => {
|
||||
if (tab === "revisions" && selectedRevision.id !== patch.id) {
|
||||
return `rad patch checkout ${formatOid(patch.id)} --revision ${formatOid(selectedRevision.id)}`;
|
||||
} else {
|
||||
return `rad patch checkout ${formatOid(patch.id)}`;
|
||||
}
|
||||
});
|
||||
const project = $derived(repo.payloads["xyz.radicle.project"]!);
|
||||
|
||||
async function updateTitle(newTitle: string) {
|
||||
@@ -334,28 +322,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
{#snippet icons(status: PatchStatus | undefined)}
|
||||
<div class="icon" style:color={status ? patchStatusColor[status] : undefined}>
|
||||
<Icon
|
||||
name={status === undefined || status === "open"
|
||||
? "patch"
|
||||
: `patch-${status}`} />
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
{#snippet counters(status: PatchStatus | undefined)}
|
||||
<div style:margin-left="auto" style:padding-left="0.25rem">
|
||||
{#if status}
|
||||
{project.meta.patches[status]}
|
||||
{:else}
|
||||
{project.meta.patches.draft +
|
||||
project.meta.patches.open +
|
||||
project.meta.patches.archived +
|
||||
project.meta.patches.merged}
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<Layout {config} loadMoreSecondColumn={loadMoreTeasers}>
|
||||
{#snippet headerCenter()}
|
||||
<CopyableId id={patch.id} />
|
||||
@@ -410,44 +376,12 @@
|
||||
</div>
|
||||
{#if showFilters}
|
||||
<div class="global-flex" style:margin="1rem 0">
|
||||
<Popover popoverPositionLeft="0" popoverPositionTop="3rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<OutlineButton variant="ghost" {onclick} styleHeight="2.5rem">
|
||||
{@render icons(status)}
|
||||
{status ? capitalize(status) : "All"}
|
||||
{@render counters(status)}
|
||||
<Icon name="chevron-down" />
|
||||
</OutlineButton>
|
||||
{/snippet}
|
||||
|
||||
{#snippet popover()}
|
||||
<Border variant="ghost">
|
||||
<DropdownList
|
||||
items={[
|
||||
undefined,
|
||||
"draft",
|
||||
"open",
|
||||
"archived",
|
||||
"merged",
|
||||
] as const}>
|
||||
{#snippet item(state)}
|
||||
<DropdownListItem
|
||||
styleGap="0.5rem"
|
||||
styleMinHeight="2.5rem"
|
||||
selected={status === state}
|
||||
onclick={async () => {
|
||||
await loadPatches(state);
|
||||
closeFocused();
|
||||
}}>
|
||||
{@render icons(state)}
|
||||
{state ? capitalize(state) : "All"}
|
||||
{@render counters(state)}
|
||||
</DropdownListItem>
|
||||
{/snippet}
|
||||
</DropdownList>
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
<PatchStateFilterButton
|
||||
counters={project.meta.patches}
|
||||
{status}
|
||||
select={async selectedState => {
|
||||
await loadPatches(selectedState);
|
||||
}} />
|
||||
{#if patchTeasers.length > 0}
|
||||
<TextInput
|
||||
onFocus={async () => {
|
||||
@@ -562,28 +496,11 @@
|
||||
allowedToEdit={true}
|
||||
title={patch.title}
|
||||
cobId={patch.id} />
|
||||
<div class="txt-small" style:margin-left="auto" style:z-index="40">
|
||||
<Popover popoverPositionRight="0" popoverPositionTop="3rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<Button styleHeight="2.5rem" variant="secondary" {onclick}>
|
||||
<Icon name="checkout" />Checkout patch<Icon
|
||||
name="chevron-down" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
{#snippet popover()}
|
||||
<Border
|
||||
styleAlignItems="flex-start"
|
||||
styleBackgroundColor="var(--color-background-float)"
|
||||
styleFlexDirection="column"
|
||||
styleGap="0.5rem"
|
||||
stylePadding="1rem"
|
||||
styleWidth="max-content"
|
||||
variant="ghost">
|
||||
To checkout this patch in your working copy, run:
|
||||
<Command command={checkoutCommand} styleWidth="100%" />
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
<div style:margin-left="auto" style:z-index="40">
|
||||
<CheckoutPatchButton
|
||||
{tab}
|
||||
selectedRevisionId={selectedRevision.id}
|
||||
patchId={patch.id} />
|
||||
</div>
|
||||
</div>
|
||||
<Border variant="ghost" styleGap="0">
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
<script lang="ts">
|
||||
import type { Config } from "@bindings/config/Config";
|
||||
import type { RepoInfo } from "@bindings/repo/RepoInfo";
|
||||
import type { Readme } from "@bindings/repo/Readme";
|
||||
import type { RepoInfo } from "@bindings/repo/RepoInfo";
|
||||
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import Button from "@app/components/Button.svelte";
|
||||
import Command from "@app/components/Command.svelte";
|
||||
import CheckoutRepoButton from "@app/components/CheckoutRepoButton.svelte";
|
||||
import CopyableId from "@app/components/CopyableId.svelte";
|
||||
import File from "@app/components/File.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import Layout from "./Layout.svelte";
|
||||
import Markdown from "@app/components/Markdown.svelte";
|
||||
import Path from "@app/components/Path.svelte";
|
||||
import Popover from "@app/components/Popover.svelte";
|
||||
import RepoHomeSecondColumn from "@app/components/RepoHomeSecondColumn.svelte";
|
||||
import RepoMetadata from "@app/components/RepoMetadata.svelte";
|
||||
|
||||
@@ -55,28 +53,8 @@
|
||||
style:font-weight="var(--font-weight-medium)">
|
||||
{project.data.name}
|
||||
</div>
|
||||
<div class="global-flex txt-small" style:margin-left="auto">
|
||||
<Popover popoverPositionRight="0" popoverPositionTop="3rem">
|
||||
{#snippet toggle(onclick)}
|
||||
<Button styleHeight="2.5rem" variant="secondary" {onclick}>
|
||||
<Icon name="checkout" />Checkout repo<Icon name="chevron-down" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
|
||||
{#snippet popover()}
|
||||
<Border
|
||||
styleAlignItems="flex-start"
|
||||
styleBackgroundColor="var(--color-background-float)"
|
||||
styleFlexDirection="column"
|
||||
styleGap="0.5rem"
|
||||
stylePadding="1rem"
|
||||
styleWidth="max-content"
|
||||
variant="ghost">
|
||||
To checkout a working copy of this repo, run:
|
||||
<Command command={`rad checkout ${repo.rid}`} styleWidth="100%" />
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
<div class="global-flex" style:margin-left="auto">
|
||||
<CheckoutRepoButton rid={repo.rid} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user