Skip to content

Dark theme improvements #226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { ScrollArea } from "@/components/ui/scroll-area";
import { useKeymapExtension } from "@/hooks/useKeymapExtension";
import { useNonEmptyQueryParam } from "@/hooks/useNonEmptyQueryParam";
import { useSyntaxHighlightingExtension } from "@/hooks/useSyntaxHighlightingExtension";
import { useThemeNormalized } from "@/hooks/useThemeNormalized";
import { search } from "@codemirror/search";
import CodeMirror, { Decoration, DecorationSet, EditorSelection, EditorView, ReactCodeMirrorRef, SelectionRange, StateField, ViewUpdate } from "@uiw/react-codemirror";
import { useEffect, useMemo, useRef, useState } from "react";
import { EditorContextMenu } from "../../components/editorContextMenu";
import { useCodeMirrorTheme } from "@/hooks/useCodeMirrorTheme";

interface CodePreviewProps {
path: string;
Expand Down Expand Up @@ -119,7 +119,7 @@ export const CodePreview = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [highlightRange, isEditorCreated]);

const { theme } = useThemeNormalized();
const theme = useCodeMirrorTheme();

return (
<ScrollArea className="h-full overflow-auto flex-1">
Expand All @@ -132,7 +132,7 @@ export const CodePreview = ({
value={source}
extensions={extensions}
readOnly={true}
theme={theme === "dark" ? "dark" : "light"}
theme={theme}
>
{editorRef.current && editorRef.current.view && currentSelection && (
<EditorContextMenu
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/app/[domain]/browse/[...path]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FileHeader } from "@/app/[domain]/components/fireHeader";
import { FileHeader } from "@/app/[domain]/components/fileHeader";
import { TopBar } from "@/app/[domain]/components/topBar";
import { Separator } from '@/components/ui/separator';
import { getFileSource, listRepositories } from '@/lib/server/searchService';
Expand Down
6 changes: 3 additions & 3 deletions packages/web/src/app/[domain]/components/configEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { ScrollArea } from "@/components/ui/scroll-area";
import { useKeymapExtension } from "@/hooks/useKeymapExtension";
import { useThemeNormalized } from "@/hooks/useThemeNormalized";
import { json, jsonLanguage, jsonParseLinter } from "@codemirror/lang-json";
import { linter } from "@codemirror/lint";
import { EditorView, hoverTooltip } from "@codemirror/view";
Expand All @@ -14,6 +13,7 @@ import { Schema } from "ajv";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import useCaptureEvent from "@/hooks/useCaptureEvent";
import { CodeHostType } from "@/lib/utils";
import { useCodeMirrorTheme } from "@/hooks/useCodeMirrorTheme";

export type QuickActionFn<T> = (previous: T) => T;
export type QuickAction<T> = {
Expand Down Expand Up @@ -119,7 +119,7 @@ const ConfigEditor = <T,>(props: ConfigEditorProps<T>, forwardedRef: Ref<ReactCo
);

const keymapExtension = useKeymapExtension(editorRef.current?.view);
const { theme } = useThemeNormalized();
const theme = useCodeMirrorTheme();

// ⚠️ DISGUSTING HACK AHEAD ⚠️
// Background: When navigating to the /connections/:id?tab=settings page, we were hitting a 500 error with the following
Expand Down Expand Up @@ -251,7 +251,7 @@ const ConfigEditor = <T,>(props: ConfigEditorProps<T>, forwardedRef: Ref<ReactCo
customAutocompleteStyle,
...jsonSchemaExtensions,
]}
theme={theme === "dark" ? "dark" : "light"}
theme={theme}
/>
</ScrollArea>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export const FileHeader = ({
branchDisplayName,
branchDisplayTitle,
}: FileHeaderProps) => {

const info = getRepoCodeHostInfo(repo);

return (
Expand All @@ -47,7 +46,7 @@ export const FileHeader = ({
</Link>
{branchDisplayName && (
<p
className="text-xs font-semibold text-gray-500 dark:text-gray-400 mt-0.5 flex items-center gap-0.5"
className="text-xs font-semibold text-gray-500 dark:text-gray-400 mt-[3px] flex items-center gap-0.5"
title={branchDisplayTitle}
>
{/* hack since to make the @ symbol look more centered with the text */}
Expand All @@ -64,7 +63,9 @@ export const FileHeader = ({
</p>
)}
<span>·</span>
<div className="flex-1 flex items-center overflow-hidden">
<div
className="flex-1 flex items-center overflow-hidden mt-0.5"
>
<span className="inline-block w-full truncate-start font-mono text-sm">
{!fileNameHighlightRange ?
fileName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import { EditorContextMenu } from "@/app/[domain]/components/editorContextMenu";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { useCodeMirrorTheme } from "@/hooks/useCodeMirrorTheme";
import { useKeymapExtension } from "@/hooks/useKeymapExtension";
import { useSyntaxHighlightingExtension } from "@/hooks/useSyntaxHighlightingExtension";
import { useThemeNormalized } from "@/hooks/useThemeNormalized";
import { gutterWidthExtension } from "@/lib/extensions/gutterWidthExtension";
import { highlightRanges, searchResultHighlightExtension } from "@/lib/extensions/searchResultHighlightExtension";
import { SearchResultFileMatch } from "@/lib/types";
Expand Down Expand Up @@ -44,8 +44,8 @@ export const CodePreview = ({
}: CodePreviewProps) => {
const editorRef = useRef<ReactCodeMirrorRef>(null);

const { theme } = useThemeNormalized();
const [gutterWidth, setGutterWidth] = useState(0);
const theme = useCodeMirrorTheme();

const keymapExtension = useKeymapExtension(editorRef.current?.view);
const syntaxHighlighting = useSyntaxHighlightingExtension(file?.language ?? '', editorRef.current?.view);
Expand Down Expand Up @@ -106,7 +106,7 @@ export const CodePreview = ({

return (
<div className="flex flex-col h-full">
<div className="flex flex-row bg-cyan-200 dark:bg-cyan-900 items-center justify-between pr-3 py-0.5">
<div className="flex flex-row bg-accent items-center justify-between pr-3 py-0.5 mt-7">

{/* Gutter icon */}
<div className="flex flex-row">
Expand Down Expand Up @@ -178,8 +178,8 @@ export const CodePreview = ({
className="relative"
readOnly={true}
value={file?.content}
theme={theme === "dark" ? "dark" : "light"}
extensions={extensions}
theme={theme}
>
{
editorRef.current?.view &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useQuery } from "@tanstack/react-query";
import { CodePreview, CodePreviewFile } from "./codePreview";
import { SearchResultFile } from "@/lib/types";
import { useDomain } from "@/hooks/useDomain";

import { SymbolIcon } from "@radix-ui/react-icons";
interface CodePreviewPanelProps {
fileMatch?: SearchResultFile;
onClose: () => void;
Expand All @@ -24,7 +24,7 @@ export const CodePreviewPanel = ({
}: CodePreviewPanelProps) => {
const domain = useDomain();

const { data: file } = useQuery({
const { data: file, isLoading } = useQuery({
queryKey: ["source", fileMatch?.FileName, fileMatch?.Repository, fileMatch?.Branches],
queryFn: async (): Promise<CodePreviewFile | undefined> => {
if (!fileMatch) {
Expand Down Expand Up @@ -88,6 +88,13 @@ export const CodePreviewPanel = ({
enabled: fileMatch !== undefined,
});

if (isLoading) {
return <div className="flex flex-col items-center justify-center h-full">
<SymbolIcon className="h-6 w-6 animate-spin" />
<p className="font-semibold text-center">Loading...</p>
</div>
}

return (
<CodePreview
file={file}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const Entry = ({
)}
<p className="overflow-hidden text-ellipsis whitespace-nowrap">{displayName}</p>
</div>
<div className="px-2 py-0.5 bg-gray-100 dark:bg-gray-800 text-sm rounded-md">
<div className="px-2 py-0.5 bg-accent text-sm rounded-md">
{countText}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
import { getCodemirrorLanguage } from "@/lib/codemirrorLanguage";
import { lineOffsetExtension } from "@/lib/extensions/lineOffsetExtension";
import { SearchResultRange } from "@/lib/types";
import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
import { EditorState, StateField, Transaction } from "@codemirror/state";
import { defaultLightThemeOption, oneDarkHighlightStyle, oneDarkTheme } from "@uiw/react-codemirror";
import { Decoration, DecorationSet, EditorView, lineNumbers } from "@codemirror/view";
import { useMemo, useRef } from "react";
import { LightweightCodeMirror, CodeMirrorRef } from "./lightweightCodeMirror";
import { useThemeNormalized } from "@/hooks/useThemeNormalized";
import { useCodeMirrorTheme } from "@/hooks/useCodeMirrorTheme";

const markDecoration = Decoration.mark({
class: "cm-searchMatch-selected"
Expand All @@ -29,19 +27,13 @@ export const CodePreview = ({
lineOffset,
}: CodePreviewProps) => {
const editorRef = useRef<CodeMirrorRef>(null);
const { theme } = useThemeNormalized();
const theme = useCodeMirrorTheme();

const extensions = useMemo(() => {
const codemirrorExtension = getCodemirrorLanguage(language);
return [
EditorView.editable.of(false),
...(theme === 'dark' ? [
syntaxHighlighting(oneDarkHighlightStyle),
oneDarkTheme,
] : [
syntaxHighlighting(defaultHighlightStyle),
defaultLightThemeOption,
]),
theme,
lineNumbers(),
lineOffsetExtension(lineOffset),
codemirrorExtension ? codemirrorExtension : [],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { FileHeader } from "@/app/[domain]/components/fireHeader";
import { FileHeader } from "@/app/[domain]/components/fileHeader";
import { Separator } from "@/components/ui/separator";
import { Repository, SearchResultFile } from "@/lib/types";
import { DoubleArrowDownIcon, DoubleArrowUpIcon } from "@radix-ui/react-icons";
Expand All @@ -17,6 +17,7 @@ interface FileMatchContainerProps {
onShowAllMatchesButtonClicked: () => void;
isBranchFilteringEnabled: boolean;
repoMetadata: Record<string, Repository>;
yOffset: number;
}

export const FileMatchContainer = ({
Expand All @@ -27,6 +28,7 @@ export const FileMatchContainer = ({
onShowAllMatchesButtonClicked,
isBranchFilteringEnabled,
repoMetadata,
yOffset,
}: FileMatchContainerProps) => {

const matchCount = useMemo(() => {
Expand Down Expand Up @@ -92,7 +94,10 @@ export const FileMatchContainer = ({
<div>
{/* Title */}
<div
className="top-0 bg-cyan-200 dark:bg-cyan-900 primary-foreground px-2 py-0.5 flex flex-row items-center justify-between cursor-pointer"
className="bg-accent primary-foreground px-2 py-0.5 flex flex-row items-center justify-between cursor-pointer sticky top-0 z-10"
style={{
top: `-${yOffset}px`,
}}
onClick={() => {
onOpenFile();
}}
Expand All @@ -119,7 +124,7 @@ export const FileMatchContainer = ({
}}
/>
{(index !== matches.length - 1 || isMoreContentButtonVisible) && (
<Separator className="dark:bg-gray-400" />
<Separator className="bg-accent" />
)}
</div>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,36 +124,40 @@ export const SearchResultsPanel = ({
position: "relative",
}}
>
{virtualizer.getVirtualItems().map((virtualRow) => (
<div
key={virtualRow.key}
data-index={virtualRow.index}
ref={virtualizer.measureElement}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
transform: `translateY(${virtualRow.start}px)`,
}}
>
<FileMatchContainer
file={fileMatches[virtualRow.index]}
onOpenFile={() => {
onOpenFileMatch(fileMatches[virtualRow.index]);
}}
onMatchIndexChanged={(matchIndex) => {
onMatchIndexChanged(matchIndex);
}}
showAllMatches={showAllMatchesStates[virtualRow.index]}
onShowAllMatchesButtonClicked={() => {
onShowAllMatchesButtonClicked(virtualRow.index);
{virtualizer.getVirtualItems().map((virtualRow) => {
const file = fileMatches[virtualRow.index];
return (
<div
key={virtualRow.key}
data-index={virtualRow.index}
ref={virtualizer.measureElement}
style={{
position: 'absolute',
transform: `translateY(${virtualRow.start}px)`,
top: 0,
left: 0,
width: '100%',
}}
isBranchFilteringEnabled={isBranchFilteringEnabled}
repoMetadata={repoMetadata}
/>
</div>
))}
>
<FileMatchContainer
file={file}
onOpenFile={() => {
onOpenFileMatch(file);
}}
onMatchIndexChanged={(matchIndex) => {
onMatchIndexChanged(matchIndex);
}}
showAllMatches={showAllMatchesStates[virtualRow.index]}
onShowAllMatchesButtonClicked={() => {
onShowAllMatchesButtonClicked(virtualRow.index);
}}
isBranchFilteringEnabled={isBranchFilteringEnabled}
repoMetadata={repoMetadata}
yOffset={virtualRow.start}
/>
</div>
)
})}
</div>
{isLoadMoreButtonVisible && (
<div className="p-3">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { EditorState, Extension, StateEffect } from "@codemirror/state";
import { EditorView } from "@codemirror/view";
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";

interface CodeMirrorProps {
value?: string;
Expand All @@ -29,14 +29,14 @@ const LightweightCodeMirror = forwardRef<CodeMirrorRef, CodeMirrorProps>(({
className,
}, ref) => {
const editor = useRef<HTMLDivElement | null>(null);
const [view, setView] = useState<EditorView>();
const [state, setState] = useState<EditorState>();
const viewRef = useRef<EditorView>();
const stateRef = useRef<EditorState>();

useImperativeHandle(ref, () => ({
editor: editor.current,
state,
view,
}), [editor, state, view]);
state: stateRef.current,
view: viewRef.current,
}), []);

useEffect(() => {
if (!editor.current) {
Expand All @@ -47,31 +47,26 @@ const LightweightCodeMirror = forwardRef<CodeMirrorRef, CodeMirrorProps>(({
extensions: [], /* extensions are explicitly left out here */
doc: value,
});
setState(state);
stateRef.current = state;

const view = new EditorView({
state,
parent: editor.current,
});
setView(view);

// console.debug(`[CM] Editor created.`);
viewRef.current = view;

return () => {
view.destroy();
setView(undefined);
setState(undefined);
// console.debug(`[CM] Editor destroyed.`);
viewRef.current = undefined;
stateRef.current = undefined;
}

}, [value]);

useEffect(() => {
if (view) {
view.dispatch({ effects: StateEffect.reconfigure.of(extensions ?? []) });
// console.debug(`[CM] Editor reconfigured.`);
if (viewRef.current) {
viewRef.current.dispatch({ effects: StateEffect.reconfigure.of(extensions ?? []) });
}
}, [extensions, view]);
}, [extensions]);

return (
<div
Expand Down
Loading