mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-11 20:05:25 +00:00
Syntax reference guide (#169)
This commit is contained in:
parent
b96fffcc83
commit
6c77278498
14 changed files with 544 additions and 41 deletions
|
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Added a syntax reference guide. The guide can be opened using the hotkey "Cmd + /" ("Ctrl + /" on Windows). ([#169](https://github.com/sourcebot-dev/sourcebot/pull/169))
|
||||
|
||||
## [2.7.1] - 2025-01-15
|
||||
|
||||
### Fixed
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
"@hookform/resolvers": "^3.9.0",
|
||||
"@iconify/react": "^5.1.0",
|
||||
"@iizukak/codemirror-lang-wgsl": "^0.3.0",
|
||||
"@radix-ui/react-dialog": "^1.1.4",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export const FileHeader = ({
|
|||
{info?.icon ? (
|
||||
<Image
|
||||
src={info.icon}
|
||||
alt={info.costHostName}
|
||||
alt={info.codeHostName}
|
||||
className={`w-4 h-4 ${info.iconClassName}`}
|
||||
/>
|
||||
): (
|
||||
|
|
|
|||
16
packages/web/src/app/components/keyboardShortcutHint.tsx
Normal file
16
packages/web/src/app/components/keyboardShortcutHint.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import React from 'react'
|
||||
|
||||
interface KeyboardShortcutHintProps {
|
||||
shortcut: string
|
||||
label?: string
|
||||
}
|
||||
|
||||
export function KeyboardShortcutHint({ shortcut, label }: KeyboardShortcutHintProps) {
|
||||
return (
|
||||
<div className="inline-flex items-center" aria-label={label || `Keyboard shortcut: ${shortcut}`}>
|
||||
<kbd className="px-2 py-1 text-xs font-semibold border rounded-md">
|
||||
{shortcut}
|
||||
</kbd>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ const RepositoryBadge = ({
|
|||
return {
|
||||
repoIcon: <Image
|
||||
src={info.icon}
|
||||
alt={info.costHostName}
|
||||
alt={info.codeHostName}
|
||||
className={`w-4 h-4 ${info.iconClassName}`}
|
||||
/>,
|
||||
displayName: info.displayName,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import { useSuggestionModeAndQuery } from "./useSuggestionModeAndQuery";
|
|||
import { Separator } from "@/components/ui/separator";
|
||||
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
|
||||
import { Toggle } from "@/components/ui/toggle";
|
||||
import { KeyboardShortcutHint } from "../keyboardShortcutHint";
|
||||
|
||||
interface SearchBarProps {
|
||||
className?: string;
|
||||
|
|
@ -71,7 +72,7 @@ const searchBarKeymap: readonly KeyBinding[] = ([
|
|||
] as KeyBinding[]).concat(historyKeymap);
|
||||
|
||||
const searchBarContainerVariants = cva(
|
||||
"search-bar-container flex items-center py-0.5 px-1 border rounded-md relative",
|
||||
"search-bar-container flex items-center justify-center py-0.5 px-2 border rounded-md relative",
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
|
|
@ -264,6 +265,7 @@ export const SearchBar = ({
|
|||
indentWithTab={false}
|
||||
autoFocus={autoFocus ?? false}
|
||||
/>
|
||||
<KeyboardShortcutHint shortcut="/" />
|
||||
<SearchSuggestionsBox
|
||||
ref={suggestionBoxRef}
|
||||
query={query}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { IconType } from "react-icons/lib";
|
|||
import { VscFile, VscFilter, VscRepo, VscSymbolMisc } from "react-icons/vsc";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { KeyboardShortcutHint } from "../keyboardShortcutHint";
|
||||
|
||||
export type Suggestion = {
|
||||
value: string;
|
||||
|
|
@ -337,7 +338,7 @@ const SearchSuggestionsBox = forwardRef(({
|
|||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
>
|
||||
<p className="text-muted-foreground text-sm mb-1">
|
||||
<p className="text-muted-foreground text-sm mb-2">
|
||||
{suggestionModeText}
|
||||
</p>
|
||||
{isLoadingSuggestions ? (
|
||||
|
|
@ -385,20 +386,30 @@ const SearchSuggestionsBox = forwardRef(({
|
|||
)}
|
||||
</div>
|
||||
))}
|
||||
{isFocused && (
|
||||
<>
|
||||
<Separator
|
||||
orientation="horizontal"
|
||||
className="my-2"
|
||||
/>
|
||||
<div className="flex flex-row items-center justify-end mt-1">
|
||||
<span className="text-muted-foreground text-xs">
|
||||
Press <kbd className="font-mono text-xs font-bold">Enter</kbd> to select
|
||||
</span>
|
||||
<div className="flex flex-row items-center justify-between mt-1">
|
||||
<div className="flex flex-row gap-1.5 items-center">
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Syntax help:
|
||||
</p>
|
||||
<div className="flex flex-row gap-0.5 items-center">
|
||||
<KeyboardShortcutHint shortcut="⌘" />
|
||||
<KeyboardShortcutHint shortcut="/" />
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
{isFocused && (
|
||||
<span className="flex flex-row gap-1.5 items-center">
|
||||
<KeyboardShortcutHint shortcut="↵" />
|
||||
<span className="text-muted-foreground text-sm font-medium">
|
||||
to select
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
|
||||
|
|
|
|||
244
packages/web/src/app/components/syntaxReferenceGuide.tsx
Normal file
244
packages/web/src/app/components/syntaxReferenceGuide.tsx
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
'use client';
|
||||
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import clsx from "clsx";
|
||||
import Link from "next/link";
|
||||
import { useCallback, useRef, useState } from "react";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
|
||||
const LINGUIST_LINK = "https://github.com/github-linguist/linguist/blob/main/lib/linguist/languages.yml";
|
||||
const CTAGS_LINK = "https://ctags.io/";
|
||||
|
||||
export const SyntaxReferenceGuide = () => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const previousFocusedElement = useRef<HTMLElement | null>(null);
|
||||
|
||||
const openDialog = useCallback(() => {
|
||||
previousFocusedElement.current = document.activeElement as HTMLElement;
|
||||
setIsOpen(true);
|
||||
}, []);
|
||||
|
||||
const closeDialog = useCallback(() => {
|
||||
setIsOpen(false);
|
||||
|
||||
// @note: Without requestAnimationFrame, focus was not being returned
|
||||
// to codemirror elements for some reason.
|
||||
requestAnimationFrame(() => {
|
||||
previousFocusedElement.current?.focus();
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleOpenChange = useCallback((isOpen: boolean) => {
|
||||
if (isOpen) {
|
||||
openDialog();
|
||||
} else {
|
||||
closeDialog();
|
||||
}
|
||||
}, [closeDialog, openDialog]);
|
||||
|
||||
useHotkeys("mod+/", (event) => {
|
||||
event.preventDefault();
|
||||
handleOpenChange(!isOpen);
|
||||
}, {
|
||||
enableOnFormTags: true,
|
||||
enableOnContentEditable: true,
|
||||
description: "Open Syntax Reference Guide",
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
onOpenChange={handleOpenChange}
|
||||
>
|
||||
<DialogContent
|
||||
className="max-h-[80vh] max-w-[700px] overflow-scroll"
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Syntax Reference Guide</DialogTitle>
|
||||
<DialogDescription className="text-sm text-foreground">
|
||||
Queries consist of space-seperated regular expressions. Wrapping expressions in <Code>{`""`}</Code> combines them. By default, a file must have at least one match for each expression to be included.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="py-2">Example</TableHead>
|
||||
<TableHead className="py-2">Explanation</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="py-2"><Code>foo</Code></TableCell>
|
||||
<TableCell className="py-2">Match files with regex <Code>/foo/</Code></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="py-2"><Code>foo bar</Code></TableCell>
|
||||
<TableCell className="py-2">Match files with regex <Code>/foo/</Code> <b>and</b> <Code>/bar/</Code></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="py-2"><Code>{`"foo bar"`}</Code></TableCell>
|
||||
<TableCell className="py-2">Match files with regex <Code>/foo bar/</Code></TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<Separator className="my-2"/>
|
||||
<p className="text-sm">
|
||||
{`Multiple expressions can be or'd together with `}<Code>or</Code>, negated with <Code>-</Code>, or grouped with <Code>()</Code>.
|
||||
</p>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="py-2">Example</TableHead>
|
||||
<TableHead className="py-2">Explanation</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="py-2"><Code>foo <Highlight>or</Highlight> bar</Code></TableCell>
|
||||
<TableCell className="py-2">Match files with regex <Code>/foo/</Code> <b>or</b> <Code>/bar/</Code></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="py-2"><Code>foo -bar</Code></TableCell>
|
||||
<TableCell className="py-2">Match files with regex <Code>/foo/</Code> but <b>not</b> <Code>/bar/</Code></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="py-2"><Code>foo (bar <Highlight>or</Highlight> baz)</Code></TableCell>
|
||||
<TableCell className="py-2">Match files with regex <Code>/foo/</Code> <b>and</b> either <Code>/bar/</Code> <b>or</b> <Code>/baz/</Code></TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<Separator className="my-2"/>
|
||||
<p className="text-sm">
|
||||
Expressions can be prefixed with certain keywords to modify search behavior. Some keywords can be negated using the <Code>-</Code> prefix.
|
||||
</p>
|
||||
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="py-2">Prefix</TableHead>
|
||||
<TableHead className="py-2">Description</TableHead>
|
||||
<TableHead className="py-2 w-[175px]">Example</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="py-2"><Code><Highlight>file:</Highlight></Code></TableCell>
|
||||
<TableCell className="py-2">Filter results from filepaths that match the regex. By default all files are searched.</TableCell>
|
||||
<TableCell className="py-2">
|
||||
<div className="flex flex-col gap-1">
|
||||
<Code
|
||||
title="Filter results to filepaths that match regex /README/"
|
||||
>
|
||||
<Highlight>file:</Highlight>README
|
||||
</Code>
|
||||
<Code
|
||||
title="Filter results to filepaths that match regex /my file/"
|
||||
>
|
||||
<Highlight>file:</Highlight>{`"my file"`}
|
||||
</Code>
|
||||
<Code
|
||||
title="Ignore results from filepaths match regex /test\.ts$/"
|
||||
>
|
||||
<Highlight>-file:</Highlight>test\.ts$
|
||||
</Code>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="py-2"><Code><Highlight>repo:</Highlight></Code></TableCell>
|
||||
<TableCell className="py-2">Filter results from repos that match the regex. By default all repos are searched.</TableCell>
|
||||
<TableCell className="py-2">
|
||||
<div className="flex flex-col gap-1">
|
||||
<Code
|
||||
title="Filter results to repos that match regex /linux/"
|
||||
>
|
||||
<Highlight>repo:</Highlight>linux
|
||||
</Code>
|
||||
<Code
|
||||
title="Ignore results from repos that match regex /^web\/.*/"
|
||||
>
|
||||
<Highlight>-repo:</Highlight>^web/.*
|
||||
</Code>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="py-2"><Code><Highlight>rev:</Highlight></Code></TableCell>
|
||||
<TableCell className="py-2">Filter results from a specific branch or tag. By default <b>only</b> the default branch is searched.</TableCell>
|
||||
<TableCell className="py-2">
|
||||
<div className="flex flex-col gap-1">
|
||||
<Code
|
||||
title="Filter results to branches that match regex /beta/"
|
||||
>
|
||||
<Highlight>rev:</Highlight>beta
|
||||
</Code>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="py-2"><Code><Highlight>lang:</Highlight></Code></TableCell>
|
||||
<TableCell className="py-2">Filter results by language (as defined by <Link className="text-blue-500" href={LINGUIST_LINK}>linguist</Link>). By default all languages are searched.</TableCell>
|
||||
<TableCell className="py-2">
|
||||
<div className="flex flex-col gap-1">
|
||||
<Code
|
||||
title="Filter results to TypeScript files"
|
||||
>
|
||||
<Highlight>lang:</Highlight>TypeScript
|
||||
</Code>
|
||||
<Code
|
||||
title="Ignore results from YAML files"
|
||||
>
|
||||
<Highlight>-lang:</Highlight>YAML
|
||||
</Code>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="py-2"><Code><Highlight>sym:</Highlight></Code></TableCell>
|
||||
<TableCell className="py-2">Match symbol definitions created by <Link className="text-blue-500" href={CTAGS_LINK}>universal ctags</Link> at index time.</TableCell>
|
||||
<TableCell className="py-2">
|
||||
<div className="flex flex-col gap-1">
|
||||
<Code
|
||||
title="Filter results to symbols that match regex /\bmain\b/"
|
||||
>
|
||||
<Highlight>sym:</Highlight>\bmain\b
|
||||
</Code>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
const Code = ({ children, className, title }: { children: React.ReactNode, className?: string, title?: string }) => {
|
||||
return (
|
||||
<code
|
||||
className={clsx("bg-gray-100 dark:bg-gray-700 w-fit rounded-md font-mono px-2 py-0.5", className)}
|
||||
title={title}
|
||||
>
|
||||
{children}
|
||||
</code>
|
||||
)
|
||||
}
|
||||
|
||||
const Highlight = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<span className="text-highlight">
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import { QueryClientProvider } from "./queryClientProvider";
|
|||
import { PHProvider } from "./posthogProvider";
|
||||
import { Toaster } from "@/components/ui/toaster";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { SyntaxReferenceGuide } from "./components/syntaxReferenceGuide";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Sourcebot",
|
||||
|
|
@ -41,6 +42,7 @@ export default function RootLayout({
|
|||
<Suspense>
|
||||
{children}
|
||||
</Suspense>
|
||||
<SyntaxReferenceGuide />
|
||||
</TooltipProvider>
|
||||
</QueryClientProvider>
|
||||
</ThemeProvider>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { Separator } from "@/components/ui/separator";
|
|||
import { SymbolIcon } from "@radix-ui/react-icons";
|
||||
import { UpgradeToast } from "./components/upgradeToast";
|
||||
import Link from "next/link";
|
||||
|
||||
import { KeyboardShortcutHint } from "./components/keyboardShortcutHint";
|
||||
|
||||
export default async function Home() {
|
||||
return (
|
||||
|
|
@ -96,6 +96,9 @@ export default async function Home() {
|
|||
</QueryExample>
|
||||
</HowToSection>
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
<span className="dark:text-gray-300">Reference guide: </span><KeyboardShortcutHint shortcut="⌘" /> <KeyboardShortcutHint shortcut="/" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export const FilterPanel = ({
|
|||
const Icon = info ? (
|
||||
<Image
|
||||
src={info.icon}
|
||||
alt={info.costHostName}
|
||||
alt={info.codeHostName}
|
||||
className={cn('w-4 h-4 flex-shrink-0', info.iconClassName)}
|
||||
/>
|
||||
) : (
|
||||
|
|
|
|||
122
packages/web/src/components/ui/dialog.tsx
Normal file
122
packages/web/src/components/ui/dialog.tsx
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Dialog = DialogPrimitive.Root
|
||||
|
||||
const DialogTrigger = DialogPrimitive.Trigger
|
||||
|
||||
const DialogPortal = DialogPrimitive.Portal
|
||||
|
||||
const DialogClose = DialogPrimitive.Close
|
||||
|
||||
const DialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
||||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
))
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName
|
||||
|
||||
const DialogHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-1.5 text-center sm:text-left",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogHeader.displayName = "DialogHeader"
|
||||
|
||||
const DialogFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogFooter.displayName = "DialogFooter"
|
||||
|
||||
const DialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-lg font-semibold leading-none tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
||||
|
||||
const DialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
DialogPortal,
|
||||
DialogOverlay,
|
||||
DialogClose,
|
||||
DialogTrigger,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ export const createPathWithQueryParams = (path: string, ...queryParams: [string,
|
|||
type CodeHostInfo = {
|
||||
type: "github" | "gitlab" | "gitea" | "gerrit";
|
||||
displayName: string;
|
||||
costHostName: string;
|
||||
codeHostName: string;
|
||||
repoLink: string;
|
||||
icon: string;
|
||||
iconClassName?: string;
|
||||
|
|
@ -57,7 +57,7 @@ export const getRepoCodeHostInfo = (repo?: Repository): CodeHostInfo | undefined
|
|||
return {
|
||||
type: "github",
|
||||
displayName: displayName,
|
||||
costHostName: "GitHub",
|
||||
codeHostName: "GitHub",
|
||||
repoLink: repo.URL,
|
||||
icon: githubLogo,
|
||||
iconClassName: "dark:invert",
|
||||
|
|
@ -66,7 +66,7 @@ export const getRepoCodeHostInfo = (repo?: Repository): CodeHostInfo | undefined
|
|||
return {
|
||||
type: "gitlab",
|
||||
displayName: displayName,
|
||||
costHostName: "GitLab",
|
||||
codeHostName: "GitLab",
|
||||
repoLink: repo.URL,
|
||||
icon: gitlabLogo,
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ export const getRepoCodeHostInfo = (repo?: Repository): CodeHostInfo | undefined
|
|||
return {
|
||||
type: "gitea",
|
||||
displayName: displayName,
|
||||
costHostName: "Gitea",
|
||||
codeHostName: "Gitea",
|
||||
repoLink: repo.URL,
|
||||
icon: giteaLogo,
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ export const getRepoCodeHostInfo = (repo?: Repository): CodeHostInfo | undefined
|
|||
return {
|
||||
type: "gerrit",
|
||||
displayName: displayName,
|
||||
costHostName: "Gerrit",
|
||||
codeHostName: "Gerrit",
|
||||
repoLink: repo.URL,
|
||||
icon: gerritLogo,
|
||||
}
|
||||
|
|
|
|||
134
yarn.lock
134
yarn.lock
|
|
@ -1250,6 +1250,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.0.tgz#42ef83b3b56dccad5d703ae8c42919a68798bbe2"
|
||||
integrity sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==
|
||||
|
||||
"@radix-ui/primitive@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.1.tgz#fc169732d755c7fbad33ba8d0cd7fd10c90dc8e3"
|
||||
integrity sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==
|
||||
|
||||
"@radix-ui/react-arrow@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz#744f388182d360b86285217e43b6c63633f39e7a"
|
||||
|
|
@ -1272,6 +1277,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz#656432461fc8283d7b591dcf0d79152fae9ecc74"
|
||||
integrity sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==
|
||||
|
||||
"@radix-ui/react-compose-refs@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz#6f766faa975f8738269ebb8a23bad4f5a8d2faec"
|
||||
integrity sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==
|
||||
|
||||
"@radix-ui/react-context@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.0.tgz#6df8d983546cfd1999c8512f3a8ad85a6e7fcee8"
|
||||
|
|
@ -1282,6 +1292,26 @@
|
|||
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.1.tgz#82074aa83a472353bb22e86f11bcbd1c61c4c71a"
|
||||
integrity sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==
|
||||
|
||||
"@radix-ui/react-dialog@^1.1.4":
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz#d68e977acfcc0d044b9dab47b6dd2c179d2b3191"
|
||||
integrity sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==
|
||||
dependencies:
|
||||
"@radix-ui/primitive" "1.1.1"
|
||||
"@radix-ui/react-compose-refs" "1.1.1"
|
||||
"@radix-ui/react-context" "1.1.1"
|
||||
"@radix-ui/react-dismissable-layer" "1.1.3"
|
||||
"@radix-ui/react-focus-guards" "1.1.1"
|
||||
"@radix-ui/react-focus-scope" "1.1.1"
|
||||
"@radix-ui/react-id" "1.1.0"
|
||||
"@radix-ui/react-portal" "1.1.3"
|
||||
"@radix-ui/react-presence" "1.1.2"
|
||||
"@radix-ui/react-primitive" "2.0.1"
|
||||
"@radix-ui/react-slot" "1.1.1"
|
||||
"@radix-ui/react-use-controllable-state" "1.1.0"
|
||||
aria-hidden "^1.1.1"
|
||||
react-remove-scroll "^2.6.1"
|
||||
|
||||
"@radix-ui/react-direction@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.0.tgz#a7d39855f4d077adc2a1922f9c353c5977a09cdc"
|
||||
|
|
@ -1298,6 +1328,17 @@
|
|||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
"@radix-ui/react-use-escape-keydown" "1.1.0"
|
||||
|
||||
"@radix-ui/react-dismissable-layer@1.1.3":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz#4ee0f0f82d53bf5bd9db21665799bb0d1bad5ed8"
|
||||
integrity sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==
|
||||
dependencies:
|
||||
"@radix-ui/primitive" "1.1.1"
|
||||
"@radix-ui/react-compose-refs" "1.1.1"
|
||||
"@radix-ui/react-primitive" "2.0.1"
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
"@radix-ui/react-use-escape-keydown" "1.1.0"
|
||||
|
||||
"@radix-ui/react-dropdown-menu@^2.1.1":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.2.tgz#acc49577130e3c875ef0133bd1e271ea3392d924"
|
||||
|
|
@ -1325,6 +1366,15 @@
|
|||
"@radix-ui/react-primitive" "2.0.0"
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
|
||||
"@radix-ui/react-focus-scope@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz#5c602115d1db1c4fcfa0fae4c3b09bb8919853cb"
|
||||
integrity sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==
|
||||
dependencies:
|
||||
"@radix-ui/react-compose-refs" "1.1.1"
|
||||
"@radix-ui/react-primitive" "2.0.1"
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
|
||||
"@radix-ui/react-icons@^1.3.0":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-icons/-/react-icons-1.3.0.tgz#c61af8f323d87682c5ca76b856d60c2312dbcb69"
|
||||
|
|
@ -1412,6 +1462,14 @@
|
|||
"@radix-ui/react-primitive" "2.0.0"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-portal@1.1.3":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.3.tgz#b0ea5141103a1671b715481b13440763d2ac4440"
|
||||
integrity sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==
|
||||
dependencies:
|
||||
"@radix-ui/react-primitive" "2.0.1"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-presence@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.1.tgz#98aba423dba5e0c687a782c0669dcd99de17f9b1"
|
||||
|
|
@ -1420,6 +1478,14 @@
|
|||
"@radix-ui/react-compose-refs" "1.1.0"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-presence@1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.2.tgz#bb764ed8a9118b7ec4512da5ece306ded8703cdc"
|
||||
integrity sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==
|
||||
dependencies:
|
||||
"@radix-ui/react-compose-refs" "1.1.1"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-primitive@2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz#fe05715faa9203a223ccc0be15dc44b9f9822884"
|
||||
|
|
@ -1427,6 +1493,13 @@
|
|||
dependencies:
|
||||
"@radix-ui/react-slot" "1.1.0"
|
||||
|
||||
"@radix-ui/react-primitive@2.0.1":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz#6d9efc550f7520135366f333d1e820cf225fad9e"
|
||||
integrity sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==
|
||||
dependencies:
|
||||
"@radix-ui/react-slot" "1.1.1"
|
||||
|
||||
"@radix-ui/react-roving-focus@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz#b30c59daf7e714c748805bfe11c76f96caaac35e"
|
||||
|
|
@ -1471,6 +1544,13 @@
|
|||
dependencies:
|
||||
"@radix-ui/react-compose-refs" "1.1.0"
|
||||
|
||||
"@radix-ui/react-slot@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.1.tgz#ab9a0ffae4027db7dc2af503c223c978706affc3"
|
||||
integrity sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==
|
||||
dependencies:
|
||||
"@radix-ui/react-compose-refs" "1.1.1"
|
||||
|
||||
"@radix-ui/react-toast@^1.2.2":
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-toast/-/react-toast-1.2.2.tgz#fdd8ed0b80f47d6631dfd90278fee6debc06bf33"
|
||||
|
|
@ -5078,6 +5158,14 @@ react-remove-scroll-bar@^2.3.6:
|
|||
react-style-singleton "^2.2.1"
|
||||
tslib "^2.0.0"
|
||||
|
||||
react-remove-scroll-bar@^2.3.7:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz#99c20f908ee467b385b68a3469b4a3e750012223"
|
||||
integrity sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==
|
||||
dependencies:
|
||||
react-style-singleton "^2.2.2"
|
||||
tslib "^2.0.0"
|
||||
|
||||
react-remove-scroll@2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz#fb03a0845d7768a4f1519a99fdb84983b793dc07"
|
||||
|
|
@ -5089,6 +5177,17 @@ react-remove-scroll@2.6.0:
|
|||
use-callback-ref "^1.3.0"
|
||||
use-sidecar "^1.1.2"
|
||||
|
||||
react-remove-scroll@^2.6.1:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz#2518d2c5112e71ea8928f1082a58459b5c7a2a97"
|
||||
integrity sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==
|
||||
dependencies:
|
||||
react-remove-scroll-bar "^2.3.7"
|
||||
react-style-singleton "^2.2.1"
|
||||
tslib "^2.1.0"
|
||||
use-callback-ref "^1.3.3"
|
||||
use-sidecar "^1.1.2"
|
||||
|
||||
react-resizable-panels@^2.1.1:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/react-resizable-panels/-/react-resizable-panels-2.1.4.tgz#ae1803a916ba759e483336c7bd49830f1b0cd16f"
|
||||
|
|
@ -5103,6 +5202,14 @@ react-style-singleton@^2.2.1:
|
|||
invariant "^2.2.4"
|
||||
tslib "^2.0.0"
|
||||
|
||||
react-style-singleton@^2.2.2:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz#4265608be69a4d70cfe3047f2c6c88b2c3ace388"
|
||||
integrity sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==
|
||||
dependencies:
|
||||
get-nonce "^1.0.0"
|
||||
tslib "^2.0.0"
|
||||
|
||||
react@^18:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
|
||||
|
|
@ -5536,16 +5643,7 @@ string-argv@^0.3.1:
|
|||
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
|
||||
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^4.1.0:
|
||||
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
|
|
@ -5642,14 +5740,7 @@ string_decoder@^1.1.1, string_decoder@^1.3.0:
|
|||
dependencies:
|
||||
safe-buffer "~5.2.0"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
|
|
@ -6022,6 +6113,13 @@ use-callback-ref@^1.3.0:
|
|||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
use-callback-ref@^1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz#98d9fab067075841c5b2c6852090d5d0feabe2bf"
|
||||
integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
use-sidecar@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2"
|
||||
|
|
|
|||
Loading…
Reference in a new issue