Aided stab at basic tokenizer and api setup.
This commit is contained in:
53
ui/src/components/FileViewer.tsx
Normal file
53
ui/src/components/FileViewer.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { TokenizedText, type TokenizedLine } from './TokenizedText';
|
||||
|
||||
interface TokenizedDocument {
|
||||
language: string;
|
||||
lines: TokenizedLine[];
|
||||
metadata: {
|
||||
totalLines: number;
|
||||
fileSize: number;
|
||||
language: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface FileViewerProps {
|
||||
filePath: string;
|
||||
}
|
||||
|
||||
export const FileViewer: React.FC<FileViewerProps> = ({ filePath }) => {
|
||||
const [document, setDocument] = useState<TokenizedDocument | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const loadFile = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await fetch(`/api/file?path=${encodeURIComponent(filePath)}`);
|
||||
const doc = await response.json();
|
||||
setDocument(doc);
|
||||
} catch (error) {
|
||||
console.error('Failed to load file:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadFile();
|
||||
}, [filePath]);
|
||||
|
||||
if (loading) return <div>Loading...</div>;
|
||||
if (!document) return <div>Failed to load file</div>;
|
||||
|
||||
return (
|
||||
<div className="file-viewer">
|
||||
<header className="file-header">
|
||||
<h2>{filePath}</h2>
|
||||
<span className="file-info">
|
||||
{document.metadata.language} • {document.metadata.totalLines} lines
|
||||
</span>
|
||||
</header>
|
||||
<TokenizedText lines={document.lines} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
38
ui/src/components/TokenizedText.tsx
Normal file
38
ui/src/components/TokenizedText.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
|
||||
interface Token {
|
||||
type: string;
|
||||
content: string;
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
export interface TokenizedLine {
|
||||
lineNumber: number;
|
||||
tokens: Token[];
|
||||
raw: string;
|
||||
}
|
||||
|
||||
interface TokenizedTextProps {
|
||||
lines: TokenizedLine[];
|
||||
showLineNumbers?: boolean;
|
||||
}
|
||||
|
||||
export const TokenizedText: React.FC<TokenizedTextProps> = ({ lines, showLineNumbers = true }) => {
|
||||
return (
|
||||
<div className="tokenized-text">
|
||||
{lines.map((line) => (
|
||||
<div key={line.lineNumber} className="line">
|
||||
{showLineNumbers && <span className="line-number">{line.lineNumber}</span>}
|
||||
<span className="line-content">
|
||||
{line.tokens.map((token, i) => (
|
||||
<span key={i} className={`token token-${token.type}`}>
|
||||
{token.content}
|
||||
</span>
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
43
ui/src/styles/syntax.css
Normal file
43
ui/src/styles/syntax.css
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
.tokenized-text {
|
||||
font-family: 'Monaco', 'Menlo', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.line {
|
||||
display: flex;
|
||||
min-height: 21px;
|
||||
}
|
||||
|
||||
.line-number {
|
||||
color: #858585;
|
||||
margin-right: 1rem;
|
||||
user-select: none;
|
||||
min-width: 3ch;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.line-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Syntax highlighting tokens */
|
||||
.token-keyword { color: #569cd6; font-weight: bold; }
|
||||
.token-string { color: #ce9178; }
|
||||
.token-comment { color: #6a9955; font-style: italic; }
|
||||
.token-number { color: #b5cea8; }
|
||||
.token-function { color: #dcdcaa; }
|
||||
.token-type { color: #4ec9b0; }
|
||||
.token-header { color: #569cd6; font-weight: bold; }
|
||||
.token-bold { font-weight: bold; }
|
||||
.token-italic { font-style: italic; }
|
||||
.token-link { color: #9cdcfe; text-decoration: underline; }
|
||||
.token-code-block {
|
||||
background: #2d2d2d;
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
Reference in New Issue
Block a user