mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 10:00:17 +05:30
feat(renderer): Minimap (custom overview, wired to settings.minimap)
This commit is contained in:
@@ -9,6 +9,8 @@ import { oneDark } from '@codemirror/theme-one-dark';
|
|||||||
import { useTheme } from 'next-themes';
|
import { useTheme } from 'next-themes';
|
||||||
import { lightTheme, lightHighlight } from './themes/light';
|
import { lightTheme, lightHighlight } from './themes/light';
|
||||||
import { useEditorStore } from '@/stores/editor-store';
|
import { useEditorStore } from '@/stores/editor-store';
|
||||||
|
import { useSettingsStore } from '@/stores/settings-store';
|
||||||
|
import { Minimap } from './Minimap';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
bufferId: string;
|
bufferId: string;
|
||||||
@@ -24,6 +26,7 @@ export function CodeMirrorEditor({ bufferId, initialContent, onChange, onCursorC
|
|||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
const updateContent = useEditorStore((s) => s.updateContent);
|
const updateContent = useEditorStore((s) => s.updateContent);
|
||||||
const setCursor = useEditorStore((s) => s.setCursor);
|
const setCursor = useEditorStore((s) => s.setCursor);
|
||||||
|
const minimap = useSettingsStore((s) => s.minimap);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ref.current) return;
|
if (!ref.current) return;
|
||||||
@@ -76,5 +79,10 @@ export function CodeMirrorEditor({ bufferId, initialContent, onChange, onCursorC
|
|||||||
});
|
});
|
||||||
}, [resolvedTheme]);
|
}, [resolvedTheme]);
|
||||||
|
|
||||||
return <div ref={ref} className="h-full overflow-hidden" />;
|
return (
|
||||||
|
<div className="relative h-full overflow-hidden">
|
||||||
|
<div ref={ref} className="h-full overflow-hidden" />
|
||||||
|
{minimap && <Minimap content={initialContent} />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
interface Props {
|
||||||
|
content: string;
|
||||||
|
scrollRatio?: number; // 0-1, where the viewport is
|
||||||
|
visibleRatio?: number; // 0-1, what fraction of content is visible
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Minimap({ content, scrollRatio = 0, visibleRatio = 1 }: Props) {
|
||||||
|
const lines = content.split('\n');
|
||||||
|
// Compute viewport position in the minimap
|
||||||
|
const viewportTop = Math.round(scrollRatio * 100);
|
||||||
|
const viewportHeight = Math.round(visibleRatio * 100);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-testid="minimap"
|
||||||
|
className="pointer-events-none absolute right-0 top-0 h-full w-[100px] overflow-hidden border-l border-border bg-card/30 p-1 font-mono text-[6px] leading-[8px] text-muted-foreground"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<pre className="w-full truncate whitespace-pre">
|
||||||
|
{lines.map((line, i) => (
|
||||||
|
<div key={i} data-testid="minimap-line">
|
||||||
|
{line || ' '}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</pre>
|
||||||
|
<div
|
||||||
|
data-testid="minimap-viewport"
|
||||||
|
className="pointer-events-none absolute left-0 right-0 bg-brand/15"
|
||||||
|
style={{ top: `${viewportTop}%`, height: `${Math.max(viewportHeight, 5)}%` }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { Minimap } from '@/components/editor/Minimap';
|
||||||
|
|
||||||
|
describe('Minimap', () => {
|
||||||
|
it('renders lines of content as shrunk text', () => {
|
||||||
|
const content = 'line 1\nline 2\nline 3';
|
||||||
|
render(<Minimap content={content} />);
|
||||||
|
const lines = screen.getAllByTestId('minimap-line');
|
||||||
|
expect(lines).toHaveLength(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders a viewport indicator', () => {
|
||||||
|
render(
|
||||||
|
<Minimap content={'line 1\nline 2\nline 3'} scrollRatio={0.5} visibleRatio={0.5} />
|
||||||
|
);
|
||||||
|
const indicator = screen.getByTestId('minimap-viewport');
|
||||||
|
expect(indicator).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user