diff --git a/packages/web/src/app/[domain]/components/fireHeader.tsx b/packages/web/src/app/[domain]/components/fireHeader.tsx
index 702cce58..b5df9e14 100644
--- a/packages/web/src/app/[domain]/components/fireHeader.tsx
+++ b/packages/web/src/app/[domain]/components/fireHeader.tsx
@@ -31,7 +31,7 @@ export const FileHeader = ({
{info?.icon ? (
): (
diff --git a/packages/web/src/app/[domain]/components/keyboardShortcutHint.tsx b/packages/web/src/app/[domain]/components/keyboardShortcutHint.tsx
new file mode 100644
index 00000000..f93209f1
--- /dev/null
+++ b/packages/web/src/app/[domain]/components/keyboardShortcutHint.tsx
@@ -0,0 +1,16 @@
+import React from 'react'
+
+interface KeyboardShortcutHintProps {
+ shortcut: string
+ label?: string
+}
+
+export function KeyboardShortcutHint({ shortcut, label }: KeyboardShortcutHintProps) {
+ return (
+
+
+ {shortcut}
+
+
+ )
+}
diff --git a/packages/web/src/app/[domain]/components/repositoryCarousel.tsx b/packages/web/src/app/[domain]/components/repositoryCarousel.tsx
index 038b9bbf..7d1c3a65 100644
--- a/packages/web/src/app/[domain]/components/repositoryCarousel.tsx
+++ b/packages/web/src/app/[domain]/components/repositoryCarousel.tsx
@@ -63,7 +63,7 @@ const RepositoryBadge = ({
return {
repoIcon: ,
displayName: info.displayName,
diff --git a/packages/web/src/app/[domain]/components/searchBar/searchBar.tsx b/packages/web/src/app/[domain]/components/searchBar/searchBar.tsx
index d038d905..6981c843 100644
--- a/packages/web/src/app/[domain]/components/searchBar/searchBar.tsx
+++ b/packages/web/src/app/[domain]/components/searchBar/searchBar.tsx
@@ -43,6 +43,7 @@ import { Separator } from "@/components/ui/separator";
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
import { Toggle } from "@/components/ui/toggle";
import { useDomain } from "@/hooks/useDomain";
+import { KeyboardShortcutHint } from "../keyboardShortcutHint";
interface SearchBarProps {
className?: string;
@@ -72,7 +73,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: {
@@ -266,6 +267,7 @@ export const SearchBar = ({
indentWithTab={false}
autoFocus={autoFocus ?? false}
/>
+
-
+
{suggestionModeText}
{isLoadingSuggestions ? (
@@ -385,19 +386,29 @@ const SearchSuggestionsBox = forwardRef(({
)}
))}
- {isFocused && (
- <>
-
-
-
- Press Enter to select
-
+
+
+
+
+ Syntax help:
+
+
+
+
- >
- )}
+
+ {isFocused && (
+
+
+
+ to select
+
+
+ )}
+
)
});
diff --git a/packages/web/src/app/[domain]/components/syntaxReferenceGuide.tsx b/packages/web/src/app/[domain]/components/syntaxReferenceGuide.tsx
new file mode 100644
index 00000000..d2225799
--- /dev/null
+++ b/packages/web/src/app/[domain]/components/syntaxReferenceGuide.tsx
@@ -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(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 (
+
+ )
+}
+
+const Code = ({ children, className, title }: { children: React.ReactNode, className?: string, title?: string }) => {
+ return (
+
+ {children}
+
+ )
+}
+
+const Highlight = ({ children }: { children: React.ReactNode }) => {
+ return (
+
+ {children}
+
+ )
+}
diff --git a/packages/web/src/app/[domain]/layout.tsx b/packages/web/src/app/[domain]/layout.tsx
index cc739d35..7aefbbc9 100644
--- a/packages/web/src/app/[domain]/layout.tsx
+++ b/packages/web/src/app/[domain]/layout.tsx
@@ -10,6 +10,7 @@ import { cookies, headers } from "next/headers";
import { getSelectorsByUserAgent } from "react-device-detect";
import { MobileUnsupportedSplashScreen } from "./components/mobileUnsupportedSplashScreen";
import { MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME } from "@/lib/constants";
+import { SyntaxReferenceGuide } from "./components/syntaxReferenceGuide";
interface LayoutProps {
children: React.ReactNode,
@@ -79,5 +80,10 @@ export default async function Layout({
)
}
- return children;
+ return (
+ <>
+ {children}
+
+ >
+ )
}
\ No newline at end of file
diff --git a/packages/web/src/app/[domain]/page.tsx b/packages/web/src/app/[domain]/page.tsx
index 2f9c8aae..5b374b1c 100644
--- a/packages/web/src/app/[domain]/page.tsx
+++ b/packages/web/src/app/[domain]/page.tsx
@@ -8,6 +8,7 @@ import { PageNotFound } from "./components/pageNotFound";
import { Footer } from "./components/footer";
import { SourcebotLogo } from "../components/sourcebotLogo";
import { RepositorySnapshot } from "./components/repositorySnapshot";
+import { KeyboardShortcutHint } from "./components/keyboardShortcutHint";
export default async function Home({ params: { domain } }: { params: { domain: string } }) {
const org = await getOrgFromDomain(domain);
@@ -87,6 +88,9 @@ export default async function Home({ params: { domain } }: { params: { domain: s
+
+ Reference guide:
+
diff --git a/packages/web/src/app/[domain]/search/components/filterPanel/index.tsx b/packages/web/src/app/[domain]/search/components/filterPanel/index.tsx
index 41da0cce..c3ce800b 100644
--- a/packages/web/src/app/[domain]/search/components/filterPanel/index.tsx
+++ b/packages/web/src/app/[domain]/search/components/filterPanel/index.tsx
@@ -33,7 +33,7 @@ export const FilterPanel = ({
const Icon = info ? (
) : (
diff --git a/packages/web/src/lib/utils.ts b/packages/web/src/lib/utils.ts
index 9ec548cd..44dad9b5 100644
--- a/packages/web/src/lib/utils.ts
+++ b/packages/web/src/lib/utils.ts
@@ -36,7 +36,7 @@ export type CodeHostType = "github" | "gitlab" | "gitea" | "gerrit";
type CodeHostInfo = {
type: CodeHostType;
displayName: string;
- costHostName: string;
+ codeHostName: string;
repoLink: string;
icon: string;
iconClassName?: string;
@@ -54,52 +54,7 @@ export const getRepoCodeHostInfo = (repo?: Repository): CodeHostInfo | undefined
const url = new URL(repo.URL);
const displayName = url.pathname.slice(1);
- switch (webUrlType) {
- case 'github': {
- const { src, className } = getCodeHostIcon('github')!;
- return {
- type: "github",
- displayName: displayName,
- costHostName: "GitHub",
- repoLink: repo.URL,
- icon: src,
- iconClassName: className,
- }
- }
- case 'gitlab': {
- const { src, className } = getCodeHostIcon('gitlab')!;
- return {
- type: "gitlab",
- displayName: displayName,
- costHostName: "GitLab",
- repoLink: repo.URL,
- icon: src,
- iconClassName: className,
- }
- }
- case 'gitea': {
- const { src, className } = getCodeHostIcon('gitea')!;
- return {
- type: "gitea",
- displayName: displayName,
- costHostName: "Gitea",
- repoLink: repo.URL,
- icon: src,
- iconClassName: className,
- }
- }
- case 'gitiles': {
- const { src, className } = getCodeHostIcon('gerrit')!;
- return {
- type: "gerrit",
- displayName: displayName,
- costHostName: "Gerrit",
- repoLink: repo.URL,
- icon: src,
- iconClassName: className,
- }
- }
- }
+ return _getCodeHostInfoInternal(webUrlType, displayName, repo.URL);
}
export const getRepoQueryCodeHostInfo = (repo?: RepositoryQuery): CodeHostInfo | undefined => {
@@ -108,14 +63,18 @@ export const getRepoQueryCodeHostInfo = (repo?: RepositoryQuery): CodeHostInfo |
}
const displayName = repo.repoName.split('/').slice(-2).join('/');
- switch (repo.codeHostType) {
+ return _getCodeHostInfoInternal(repo.codeHostType, displayName, repo.repoCloneUrl);
+}
+
+const _getCodeHostInfoInternal = (type: string, displayName: string, cloneUrl: string): CodeHostInfo | undefined => {
+ switch (type) {
case 'github': {
const { src, className } = getCodeHostIcon('github')!;
return {
type: "github",
displayName: displayName,
- costHostName: "GitHub",
- repoLink: repo.repoCloneUrl,
+ codeHostName: "GitHub",
+ repoLink: cloneUrl,
icon: src,
iconClassName: className,
}
@@ -125,8 +84,8 @@ export const getRepoQueryCodeHostInfo = (repo?: RepositoryQuery): CodeHostInfo |
return {
type: "gitlab",
displayName: displayName,
- costHostName: "GitLab",
- repoLink: repo.repoCloneUrl,
+ codeHostName: "GitLab",
+ repoLink: cloneUrl,
icon: src,
iconClassName: className,
}
@@ -136,8 +95,8 @@ export const getRepoQueryCodeHostInfo = (repo?: RepositoryQuery): CodeHostInfo |
return {
type: "gitea",
displayName: displayName,
- costHostName: "Gitea",
- repoLink: repo.repoCloneUrl,
+ codeHostName: "Gitea",
+ repoLink: cloneUrl,
icon: src,
iconClassName: className,
}
@@ -147,8 +106,8 @@ export const getRepoQueryCodeHostInfo = (repo?: RepositoryQuery): CodeHostInfo |
return {
type: "gerrit",
displayName: displayName,
- costHostName: "Gerrit",
- repoLink: repo.repoCloneUrl,
+ codeHostName: "Gerrit",
+ repoLink: cloneUrl,
icon: src,
iconClassName: className,
}