diff --git a/src/components/common.tsx b/src/components/common.tsx index 8fe22a9..152a87d 100644 --- a/src/components/common.tsx +++ b/src/components/common.tsx @@ -25,15 +25,18 @@ export const ToggleButton: Component<{ type="button" class={clsx( 'untangled-toggle-button inline-flex items-center gap-2 border-r border-gray-300 px-3 text-sm transition-colors last:border-r-0 dark:border-gray-700', - props.active - ? 'bg-gray-200 text-gray-900 dark:bg-gray-700 dark:text-gray-100' - : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-700/50 dark:hover:text-gray-100', + props.active ? 'untangled-toggle-button-active' : 'untangled-toggle-button-idle', )} onClick={props.onClick} > {props.label} - + {props.meta} diff --git a/src/components/repo.tsx b/src/components/repo.tsx index b49c1f6..872928e 100644 --- a/src/components/repo.tsx +++ b/src/components/repo.tsx @@ -5,6 +5,8 @@ import { ChevronRight, Circle, Columns2, + Copy, + ExternalLink, FileText, FoldVertical, Folder, @@ -1112,3 +1114,47 @@ export const BranchPill: Component<{ name: string }> = (props) => ( {props.name} ); + +export const AtUriPanel: Component<{ uri: string }> = (props) => { + const selectUri: JSX.EventHandlerUnion = (event) => { + const selection = window.getSelection(); + if (!selection) return; + + const range = document.createRange(); + range.selectNodeContents(event.currentTarget); + selection.removeAllRanges(); + selection.addRange(range); + }; + + return ( + + + AT URI + + void navigator.clipboard?.writeText(props.uri)} + > + + + + + + + + + {props.uri} + + + ); +}; diff --git a/src/index.css b/src/index.css index 8990c7a..7024a4c 100644 --- a/src/index.css +++ b/src/index.css @@ -585,6 +585,10 @@ .untangled-pr-summary-card { padding: 1rem; } + + .untangled-thread-meta { + padding: 0.25rem 0.25rem 0.5rem; + } } html, @@ -748,8 +752,69 @@ pre { border: 1px solid rgb(17 24 39); } +.untangled-at-uri-panel { + min-width: 0; +} + +.untangled-at-uri-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + margin-bottom: 0.5rem; + color: rgb(107 114 128); + font-size: 0.875rem; + font-weight: 600; + text-transform: uppercase; +} + +.untangled-at-uri-actions { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.untangled-at-uri-action { + display: inline-flex; + align-items: center; + justify-content: center; + border: 0; + background: transparent; + padding: 0; + color: rgb(107 114 128); + text-decoration: none; +} + +.untangled-at-uri-action:hover { + color: rgb(55 65 81); + text-decoration: none; +} + .untangled-at-uri { - overflow-wrap: anywhere; + display: block; + max-width: 100%; + overflow-x: auto; + white-space: nowrap; + color: rgb(55 65 81); + cursor: pointer; + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; + font-size: 0.875rem; + user-select: all; +} + +@media (prefers-color-scheme: dark) { + .untangled-at-uri-header, + .untangled-at-uri-action { + color: rgb(156 163 175); + } + + .untangled-at-uri-action:hover { + color: rgb(229 231 235); + } + + .untangled-at-uri { + color: rgb(209 213 219); + } } @@ -902,6 +967,65 @@ details[open] > .untangled-language-bar { min-height: 34px; } +.untangled-toggle-button { + background: transparent; + color: rgb(75 85 99); +} + +.untangled-toggle-button-idle:hover { + background: rgb(249 250 251); + color: rgb(17 24 39); +} + +.untangled-toggle-button-active { + background: rgb(229 231 235); + color: rgb(17 24 39); +} + +.untangled-toggle-button-active:hover { + background: rgb(243 244 246); + color: rgb(17 24 39); +} + +.untangled-toggle-button-meta-idle { + color: rgb(156 163 175); +} + +.untangled-toggle-button-meta-active, +.untangled-toggle-button-idle:hover .untangled-toggle-button-meta { + color: rgb(107 114 128); +} + +@media (prefers-color-scheme: dark) { + .untangled-toggle-button { + color: rgb(209 213 219); + } + + .untangled-toggle-button-idle:hover { + background: rgb(55 65 81 / 0.5); + color: rgb(243 244 246); + } + + .untangled-toggle-button-active { + background: rgb(55 65 81); + color: rgb(243 244 246); + } + + .untangled-toggle-button-active:hover { + background: rgb(75 85 99); + color: rgb(243 244 246); + } + + .untangled-toggle-button-meta-idle { + color: rgb(107 114 128); + } + + .untangled-toggle-button-meta-active, + .untangled-toggle-button-idle:hover .untangled-toggle-button-meta { + color: rgb(156 163 175); + } +} + .untangled-button { min-height: 30px; } @@ -980,7 +1104,7 @@ details[open] > .untangled-language-bar { .untangled-file-row { display: grid; - grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); + grid-template-columns: minmax(0, 1fr) max-content; align-items: center; gap: 1rem; padding: 0.25rem 0.5rem 0.25rem 0; @@ -995,6 +1119,7 @@ details[open] > .untangled-language-bar { .untangled-file-row-time { text-align: right; + white-space: nowrap; } .untangled-filter-grid { @@ -1888,15 +2013,6 @@ details[open] > .untangled-language-bar { grid-row: 1; } - .untangled-file-row { - grid-template-columns: minmax(0, 1fr); - gap: 0.125rem; - } - - .untangled-file-row-time { - text-align: left; - } - .untangled-file-tree-pane { border-right: 0; } diff --git a/src/pages/repo/code.tsx b/src/pages/repo/code.tsx index a30ffce..196bb69 100644 --- a/src/pages/repo/code.tsx +++ b/src/pages/repo/code.tsx @@ -901,6 +901,7 @@ export const BlobPage: Component = () => { {commit().author?.name || 'unknown author'} + · {commit().message.trim().split('\n')[0]} · {formatRelativeTime(commit().when)} diff --git a/src/pages/repo/issues.tsx b/src/pages/repo/issues.tsx index 3a4ea71..65663ac 100644 --- a/src/pages/repo/issues.tsx +++ b/src/pages/repo/issues.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx'; -import { Ban, CirclePlus, Copy, ExternalLink, LoaderCircle, MessageSquarePlus, Pencil, Reply, Search, Smile, X } from 'lucide-solid'; +import { Ban, CirclePlus, LoaderCircle, MessageSquarePlus, Pencil, Reply, Search, Smile, X } from 'lucide-solid'; import { A, useNavigate, useParams, useSearchParams } from '@solidjs/router'; import { createQuery, useQueryClient } from '@tanstack/solid-query'; import type { ResourceUri } from '@atcute/lexicons/syntax'; @@ -7,7 +7,7 @@ import { For, Match, Show, Switch, createEffect, createMemo, createSignal, type import { createIssue, createIssueComment, getIssue, listIssuesPage, parseAtUri, resolveActor, setIssueState, type RepoContext } from '../../lib/api'; import { useAuth } from '../../lib/auth'; import { Avatar, ErrorState, PaginationControls, StateBadge, ToggleButton, buttonStyles, cardStyles, inputStyles, textareaStyles } from '../../components/common'; -import { MarkdownBlock, RepoListSkeleton, RepoThreadSkeleton } from '../../components/repo'; +import { AtUriPanel, MarkdownBlock, RepoListSkeleton, RepoThreadSkeleton } from '../../components/repo'; import { RepoFrame, issueQueryKey, issuesQueryKey, useRepoQuery } from './shared'; import { REPO_LIST_PAGE_LIMIT, formatRelativeTime, getErrorMessage, issueHref, parseIntegerSearchParam, uniqueCommenters } from '../../lib/repo-utils'; import { buildIssueCommentThreads, buildIssueFilterQuery, parseIssueFilter } from './issues-helpers'; @@ -330,10 +330,6 @@ export const IssuePage: Component = () => { } }; - const copyIssueUri = async (uri: string) => { - await navigator.clipboard?.writeText(uri).catch(() => undefined); - }; - const submitReply = async (event: SubmitEvent, replyTo: ResourceUri) => { event.preventDefault(); const agent = auth.agent(); @@ -566,7 +562,7 @@ export const IssuePage: Component = () => { - + Labels @@ -591,20 +587,7 @@ export const IssuePage: Component = () => { - - - AT URI - - void copyIssueUri(detail().issue.uri)}> - - - - - - - - {detail().issue.uri} - + ); diff --git a/src/pages/repo/pulls.tsx b/src/pages/repo/pulls.tsx index b7fd6d4..764c0e0 100644 --- a/src/pages/repo/pulls.tsx +++ b/src/pages/repo/pulls.tsx @@ -20,7 +20,7 @@ import { For, Match, Show, Switch, createEffect, createMemo, createSignal, type import { compareBranches, createPull, createPullComment, fetchPullRoundPatch, getPull, getRepoBranches, listPullsPage, parseAtUri, resolveActor, setPullStatus, type RepoContext } from '../../lib/api'; import { useAuth } from '../../lib/auth'; import { Avatar, ErrorState, LoadingState, PaginationControls, StateBadge, ToggleButton, buttonStyles, cardStyles, textareaStyles } from '../../components/common'; -import { BranchPill, CommentCard, DiffView, MarkdownBlock, PullDiffSkeleton, PullDiffView, RepoListSkeleton, RepoThreadSkeleton } from '../../components/repo'; +import { AtUriPanel, BranchPill, CommentCard, DiffView, MarkdownBlock, PullDiffSkeleton, PullDiffView, RepoListSkeleton, RepoThreadSkeleton } from '../../components/repo'; import { RepoFrame, pullQueryKey, pullsQueryKey, useRepoQuery } from './shared'; import { REPO_LIST_PAGE_LIMIT, formatRelativeTime, getErrorMessage, parseIntegerSearchParam, pullHref, uniqueCommenters } from '../../lib/repo-utils'; import { buildPullFilterQuery, parsePastedPatchPrefill, parsePullFilter, type PullSourceMode } from './pulls-helpers'; @@ -916,7 +916,7 @@ export const PullPage: Component = () => { -