improve file viewing
This commit is contained in:
parent
1c2cdd2c20
commit
f2127b01b8
1 changed files with 89 additions and 32 deletions
|
@ -276,8 +276,11 @@ export default function FilePreview({ url: initialUrl = '', filename: initialFil
|
||||||
return 'yaml';
|
return 'yaml';
|
||||||
case 'csv':
|
case 'csv':
|
||||||
return 'csv';
|
return 'csv';
|
||||||
|
case 'txt':
|
||||||
|
return 'plaintext';
|
||||||
default:
|
default:
|
||||||
return extension || 'plaintext';
|
// If no extension or unrecognized extension, default to plaintext
|
||||||
|
return 'plaintext';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -332,34 +335,41 @@ export default function FilePreview({ url: initialUrl = '', filename: initialFil
|
||||||
`;
|
`;
|
||||||
}, [visibleLines]);
|
}, [visibleLines]);
|
||||||
|
|
||||||
|
const formatCodeWithLineNumbers = useCallback((code: string, language: string) => {
|
||||||
|
try {
|
||||||
|
// Use highlight.js to highlight the code
|
||||||
|
const highlighted = hljs.highlight(code, { language }).value;
|
||||||
|
const lines = highlighted.split('\n');
|
||||||
|
|
||||||
|
return lines.map((line, i) =>
|
||||||
|
`<div class="code-line">
|
||||||
|
<span class="line-number">${i + 1}</span>
|
||||||
|
<span class="line-content">${line || ' '}</span>
|
||||||
|
</div>`
|
||||||
|
).join('');
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Failed to highlight code as ${language}, falling back to plaintext`);
|
||||||
|
const plaintext = hljs.highlight(code, { language: 'plaintext' }).value;
|
||||||
|
const lines = plaintext.split('\n');
|
||||||
|
|
||||||
|
return lines.map((line, i) =>
|
||||||
|
`<div class="code-line">
|
||||||
|
<span class="line-number">${i + 1}</span>
|
||||||
|
<span class="line-content">${line || ' '}</span>
|
||||||
|
</div>`
|
||||||
|
).join('');
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const highlightCode = useCallback((code: string, language: string) => {
|
const highlightCode = useCallback((code: string, language: string) => {
|
||||||
// Skip highlighting for CSV
|
// Skip highlighting for CSV
|
||||||
if (language === 'csv') {
|
if (language === 'csv') {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return code; // Just return the code, formatting is handled in formatCodeWithLineNumbers
|
||||||
// Use highlight.js to highlight the code
|
|
||||||
const highlighted = hljs.highlight(code, { language }).value;
|
|
||||||
return highlighted;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`Failed to highlight code as ${language}, falling back to plaintext`);
|
|
||||||
return hljs.highlight(code, { language: 'plaintext' }).value;
|
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const formatCodeWithLineNumbers = useCallback((code: string, language: string) => {
|
|
||||||
const highlighted = highlightCode(code, language);
|
|
||||||
const lines = highlighted.split('\n').slice(0, visibleLines);
|
|
||||||
|
|
||||||
return lines.map((line, i) =>
|
|
||||||
`<div class="table-row">
|
|
||||||
<div class="table-cell text-right pr-4 select-none opacity-50 w-12">${i + 1}</div>
|
|
||||||
<div class="table-cell">${line || ' '}</div>
|
|
||||||
</div>`
|
|
||||||
).join('');
|
|
||||||
}, [visibleLines, highlightCode]);
|
|
||||||
|
|
||||||
const handleShowMore = useCallback(() => {
|
const handleShowMore = useCallback(() => {
|
||||||
setVisibleLines(prev => Math.min(prev + CHUNK_SIZE, content?.split('\n').length || 0));
|
setVisibleLines(prev => Math.min(prev + CHUNK_SIZE, content?.split('\n').length || 0));
|
||||||
}, [content]);
|
}, [content]);
|
||||||
|
@ -482,17 +492,64 @@ export default function FilePreview({ url: initialUrl = '', filename: initialFil
|
||||||
{filename.toLowerCase().endsWith('.csv') ? (
|
{filename.toLowerCase().endsWith('.csv') ? (
|
||||||
<div dangerouslySetInnerHTML={{ __html: renderCSVTable(content) }} />
|
<div dangerouslySetInnerHTML={{ __html: renderCSVTable(content) }} />
|
||||||
) : (
|
) : (
|
||||||
<pre className="text-sm">
|
<>
|
||||||
<code
|
<div className="file-preview-code-container text-sm">
|
||||||
className={`language-${getLanguageFromFilename(filename)}`}
|
<style>
|
||||||
dangerouslySetInnerHTML={{
|
{`
|
||||||
__html: formatCodeWithLineNumbers(
|
.file-preview-code-container {
|
||||||
content.split('\n').slice(0, visibleLines).join('\n'),
|
font-family: monospace;
|
||||||
getLanguageFromFilename(filename)
|
}
|
||||||
)
|
.file-preview-code-container .code-line {
|
||||||
}}
|
display: flex;
|
||||||
/>
|
white-space: pre;
|
||||||
</pre>
|
}
|
||||||
|
.file-preview-code-container .line-number {
|
||||||
|
user-select: none;
|
||||||
|
text-align: right;
|
||||||
|
color: rgba(115, 115, 115, 0.6);
|
||||||
|
min-width: 40px;
|
||||||
|
padding-right: 12px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.file-preview-code-container .line-content {
|
||||||
|
flex: 1;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: formatCodeWithLineNumbers(
|
||||||
|
content.split('\n').slice(0, visibleLines).join('\n'),
|
||||||
|
getLanguageFromFilename(filename)
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{content.split('\n').length > visibleLines && (
|
||||||
|
<div className="flex justify-center p-2 border-t border-base-300 bg-base-200/50">
|
||||||
|
{visibleLines < content.split('\n').length && (
|
||||||
|
<button
|
||||||
|
className="btn btn-sm btn-ghost gap-1"
|
||||||
|
onClick={handleShowMore}
|
||||||
|
>
|
||||||
|
<Icon icon="mdi:chevron-down" className="h-4 w-4" />
|
||||||
|
Show {Math.min(CHUNK_SIZE, content.split('\n').length - visibleLines)} more lines
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{visibleLines > INITIAL_LINES_TO_SHOW && (
|
||||||
|
<button
|
||||||
|
className="btn btn-sm btn-ghost gap-1 ml-2"
|
||||||
|
onClick={handleShowLess}
|
||||||
|
>
|
||||||
|
<Icon icon="mdi:chevron-up" className="h-4 w-4" />
|
||||||
|
Show less
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue