feat(nvim): display selected file in tree in the editor

This commit is contained in:
Pihkaal
2024-01-28 21:35:06 +01:00
parent 965fff6226
commit e778631828
7 changed files with 139 additions and 27 deletions

View File

@@ -14,6 +14,7 @@
"axios": "^1.6.7", "axios": "^1.6.7",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-router-dom": "^6.21.3",
"vite-tsconfig-paths": "^4.3.1", "vite-tsconfig-paths": "^4.3.1",
"zod": "^3.22.4" "zod": "^3.22.4"
}, },

31
pnpm-lock.yaml generated
View File

@@ -14,6 +14,9 @@ dependencies:
react-dom: react-dom:
specifier: 18.2.0 specifier: 18.2.0
version: 18.2.0(react@18.2.0) version: 18.2.0(react@18.2.0)
react-router-dom:
specifier: ^6.21.3
version: 6.21.3(react-dom@18.2.0)(react@18.2.0)
vite-tsconfig-paths: vite-tsconfig-paths:
specifier: ^4.3.1 specifier: ^4.3.1
version: 4.3.1(typescript@5.3.3)(vite@5.0.12) version: 4.3.1(typescript@5.3.3)(vite@5.0.12)
@@ -419,6 +422,11 @@ packages:
dev: true dev: true
optional: true optional: true
/@remix-run/router@1.14.2:
resolution: {integrity: sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg==}
engines: {node: '>=14.0.0'}
dev: false
/@rollup/rollup-android-arm-eabi@4.9.6: /@rollup/rollup-android-arm-eabi@4.9.6:
resolution: {integrity: sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==} resolution: {integrity: sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==}
cpu: [arm] cpu: [arm]
@@ -2726,6 +2734,29 @@ packages:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
dev: true dev: true
/react-router-dom@6.21.3(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-kNzubk7n4YHSrErzjLK72j0B5i969GsuCGazRl3G6j1zqZBLjuSlYBdVdkDOgzGdPIffUOc9nmgiadTEVoq91g==}
engines: {node: '>=14.0.0'}
peerDependencies:
react: '>=16.8'
react-dom: '>=16.8'
dependencies:
'@remix-run/router': 1.14.2
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-router: 6.21.3(react@18.2.0)
dev: false
/react-router@6.21.3(react@18.2.0):
resolution: {integrity: sha512-a0H638ZXULv1OdkmiK6s6itNhoy33ywxmUFT/xtSoVyf9VnC7n7+VT4LjVzdIHSaF5TIh9ylUgxMXksHTgGrKg==}
engines: {node: '>=14.0.0'}
peerDependencies:
react: '>=16.8'
dependencies:
'@remix-run/router': 1.14.2
react: 18.2.0
dev: false
/react@18.2.0: /react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}

View File

@@ -1,3 +1,4 @@
import { BrowserRouter } from "react-router-dom";
import { MusicPlayer } from "./components/MusicPlayer"; import { MusicPlayer } from "./components/MusicPlayer";
import { MusicVisualizer } from "./components/MusicVisualizer"; import { MusicVisualizer } from "./components/MusicVisualizer";
import { Nvim } from "./components/Nvim/Nvim"; import { Nvim } from "./components/Nvim/Nvim";
@@ -7,6 +8,7 @@ import { AppContextProvider } from "./context/AppContext";
function App() { function App() {
return ( return (
<AppContextProvider> <AppContextProvider>
<BrowserRouter>
<main <main
className={ className={
"insets-0 fixed flex h-screen w-screen flex-col gap-3 bg-[url(/wallpaper.jpg)] bg-cover p-3 font-body leading-[26px]" "insets-0 fixed flex h-screen w-screen flex-col gap-3 bg-[url(/wallpaper.jpg)] bg-cover p-3 font-body leading-[26px]"
@@ -33,6 +35,7 @@ function App() {
</Terminal> </Terminal>
</div> </div>
</main> </main>
</BrowserRouter>
</AppContextProvider> </AppContextProvider>
); );
} }

View File

@@ -2,19 +2,71 @@ import { useApp } from "~/context/AppContext";
import { NvimStatusBar } from "./NvimStatusBar"; import { NvimStatusBar } from "./NvimStatusBar";
import { NvimTree } from "./NvimTree"; import { NvimTree } from "./NvimTree";
import { buildFileTree } from "~/utils/filesystem"; import { buildFileTree } from "~/utils/filesystem";
import { useEffect, useState } from "react";
import axios from "axios";
import { useLocation, useNavigate } from "react-router-dom";
import { NvimEditor } from "./NvimEditor";
const fetchData = async (
branch: string,
repo: string,
file: string,
): Promise<string | null> => {
try {
const response = await axios.get<string>(
`https://raw.githubusercontent.com/pihkaal/${repo}/${branch}/${file}`,
);
return response.data;
} catch {
return null;
}
};
export const Nvim = () => { export const Nvim = () => {
const manifest = useApp(); const manifest = useApp();
const [data, setData] = useState<string | null>(null);
const location = useLocation();
const navigate = useNavigate();
useEffect(() => {
const params = new URLSearchParams(location.search);
const view = params.get("view");
if (!view) {
navigate("?view=README.md");
return;
}
const path = view.split("/");
if (path.length === 1) {
path.splice(0, 0, "pihkaal");
}
const repo = path[0]!;
const file = path[1]!;
void (async () => {
const data =
(await fetchData("main", repo, file)) ??
(await fetchData("dev", repo, file));
if (!data) {
navigate("?view=README.md");
return;
}
setData(data);
})();
}, [location, navigate]);
return ( return (
<div> <div className="flex flex-col">
<div className="flex"> <div className="flex flex-1 flex-row">
<div className="w-fit"> <div className="w-fit">
<NvimTree files={buildFileTree(manifest)} /> <NvimTree files={buildFileTree(manifest)} />
</div> </div>
<div className="flex-1"></div> <div className="flex-1">
<NvimEditor content={data} />
</div>
</div> </div>
<div className="h-fit bg-[#29293c]"> <div className="h-fit bg-[#29293c]">
<NvimStatusBar label="NORMAL" fileName="README.md" /> <NvimStatusBar label="NORMAL" fileName="README.md" />
</div> </div>

View File

@@ -0,0 +1,16 @@
import { useTerminal } from "~/context/TerminalContext";
import { TerminalRenderer } from "~/utils/terminal/renderer";
export const NvimEditor = (props: { content: string | null }) => {
const { cols: width, rows: height } = useTerminal();
const canvas = new TerminalRenderer(width * 0.8, height - 2);
if (props.content) {
props.content.split("\n").forEach((line, y) => {
canvas.write(0, y, line);
});
}
return canvas.render();
};

View File

@@ -1,4 +1,5 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useTerminal } from "~/context/TerminalContext"; import { useTerminal } from "~/context/TerminalContext";
import { import {
DEFAULT_FILE_STYLE, DEFAULT_FILE_STYLE,
@@ -23,6 +24,7 @@ const PATH_UNFOLDED: Cell = {
export const NvimTree = (props: { files: Array<File> }) => { export const NvimTree = (props: { files: Array<File> }) => {
const [selected, setSelected] = useState(0); const [selected, setSelected] = useState(0);
const [files, setFiles] = useState(props.files); const [files, setFiles] = useState(props.files);
const navigate = useNavigate();
const { cols: width, rows: height } = useTerminal(); const { cols: width, rows: height } = useTerminal();
const canvas = new TerminalRenderer(width * 0.2, height - 2, { const canvas = new TerminalRenderer(width * 0.2, height - 2, {
@@ -108,6 +110,9 @@ export const NvimTree = (props: { files: Array<File> }) => {
if (current.type === "directory") { if (current.type === "directory") {
current.folded = !current.folded; current.folded = !current.folded;
setFiles([...files]); setFiles([...files]);
} else {
//document.location.href = `?view=${current.path}`
navigate(`?view=${current.path}`);
} }
break; break;
} }

View File

@@ -25,6 +25,7 @@ export const FILE_STYLES: Record<string, Cell> = {
export type File = { export type File = {
name: string; name: string;
path: string;
} & ( } & (
| { | {
type: "file"; type: "file";
@@ -54,17 +55,20 @@ export const buildFileTree = (manifest: Manifest): Array<File> => {
project.files.forEach(file => { project.files.forEach(file => {
files.push({ files.push({
name: file, name: file,
path: file,
type: "file", type: "file",
}); });
}); });
} else { } else {
files.push({ files.push({
name: project.name, name: project.name,
path: project.name,
type: "directory", type: "directory",
folded: true, folded: true,
children: sortFiles( children: sortFiles(
project.files.map(file => ({ project.files.map(file => ({
name: file, name: file,
path: `${project.name}/${file}`,
type: "file", type: "file",
})), })),
), ),