feat(nvim): display selected file in tree in the editor
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
"axios": "^1.6.7",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"vite-tsconfig-paths": "^4.3.1",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
|
||||
31
pnpm-lock.yaml
generated
31
pnpm-lock.yaml
generated
@@ -14,6 +14,9 @@ dependencies:
|
||||
react-dom:
|
||||
specifier: 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:
|
||||
specifier: ^4.3.1
|
||||
version: 4.3.1(typescript@5.3.3)(vite@5.0.12)
|
||||
@@ -419,6 +422,11 @@ packages:
|
||||
dev: 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:
|
||||
resolution: {integrity: sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==}
|
||||
cpu: [arm]
|
||||
@@ -2726,6 +2734,29 @@ packages:
|
||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||
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:
|
||||
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
49
src/App.tsx
49
src/App.tsx
@@ -1,3 +1,4 @@
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import { MusicPlayer } from "./components/MusicPlayer";
|
||||
import { MusicVisualizer } from "./components/MusicVisualizer";
|
||||
import { Nvim } from "./components/Nvim/Nvim";
|
||||
@@ -7,32 +8,34 @@ import { AppContextProvider } from "./context/AppContext";
|
||||
function App() {
|
||||
return (
|
||||
<AppContextProvider>
|
||||
<main
|
||||
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]"
|
||||
}
|
||||
>
|
||||
<nav className="border border-red-500">toolbar</nav>
|
||||
|
||||
<Terminal className="flex-1">
|
||||
<Nvim />
|
||||
</Terminal>
|
||||
|
||||
<div className="flex gap-3">
|
||||
<Terminal className="flex-1 select-none">
|
||||
<MusicPlayer
|
||||
title="Last Tango in Kyoto"
|
||||
artist="Floating Bits"
|
||||
album="Last Tango in Kyoto"
|
||||
duration={93}
|
||||
/>
|
||||
</Terminal>
|
||||
<BrowserRouter>
|
||||
<main
|
||||
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]"
|
||||
}
|
||||
>
|
||||
<nav className="border border-red-500">toolbar</nav>
|
||||
|
||||
<Terminal className="flex-1">
|
||||
<MusicVisualizer />
|
||||
<Nvim />
|
||||
</Terminal>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div className="flex gap-3">
|
||||
<Terminal className="flex-1 select-none">
|
||||
<MusicPlayer
|
||||
title="Last Tango in Kyoto"
|
||||
artist="Floating Bits"
|
||||
album="Last Tango in Kyoto"
|
||||
duration={93}
|
||||
/>
|
||||
</Terminal>
|
||||
|
||||
<Terminal className="flex-1">
|
||||
<MusicVisualizer />
|
||||
</Terminal>
|
||||
</div>
|
||||
</main>
|
||||
</BrowserRouter>
|
||||
</AppContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,19 +2,71 @@ import { useApp } from "~/context/AppContext";
|
||||
import { NvimStatusBar } from "./NvimStatusBar";
|
||||
import { NvimTree } from "./NvimTree";
|
||||
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 = () => {
|
||||
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 (
|
||||
<div>
|
||||
<div className="flex">
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-1 flex-row">
|
||||
<div className="w-fit">
|
||||
<NvimTree files={buildFileTree(manifest)} />
|
||||
</div>
|
||||
<div className="flex-1"></div>
|
||||
<div className="flex-1">
|
||||
<NvimEditor content={data} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="h-fit bg-[#29293c]">
|
||||
<NvimStatusBar label="NORMAL" fileName="README.md" />
|
||||
</div>
|
||||
|
||||
16
src/components/Nvim/NvimEditor.tsx
Normal file
16
src/components/Nvim/NvimEditor.tsx
Normal 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();
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useTerminal } from "~/context/TerminalContext";
|
||||
import {
|
||||
DEFAULT_FILE_STYLE,
|
||||
@@ -23,6 +24,7 @@ const PATH_UNFOLDED: Cell = {
|
||||
export const NvimTree = (props: { files: Array<File> }) => {
|
||||
const [selected, setSelected] = useState(0);
|
||||
const [files, setFiles] = useState(props.files);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { cols: width, rows: height } = useTerminal();
|
||||
const canvas = new TerminalRenderer(width * 0.2, height - 2, {
|
||||
@@ -108,6 +110,9 @@ export const NvimTree = (props: { files: Array<File> }) => {
|
||||
if (current.type === "directory") {
|
||||
current.folded = !current.folded;
|
||||
setFiles([...files]);
|
||||
} else {
|
||||
//document.location.href = `?view=${current.path}`
|
||||
navigate(`?view=${current.path}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ export const FILE_STYLES: Record<string, Cell> = {
|
||||
|
||||
export type File = {
|
||||
name: string;
|
||||
path: string;
|
||||
} & (
|
||||
| {
|
||||
type: "file";
|
||||
@@ -54,17 +55,20 @@ export const buildFileTree = (manifest: Manifest): Array<File> => {
|
||||
project.files.forEach(file => {
|
||||
files.push({
|
||||
name: file,
|
||||
path: file,
|
||||
type: "file",
|
||||
});
|
||||
});
|
||||
} else {
|
||||
files.push({
|
||||
name: project.name,
|
||||
path: project.name,
|
||||
type: "directory",
|
||||
folded: true,
|
||||
children: sortFiles(
|
||||
project.files.map(file => ({
|
||||
name: file,
|
||||
path: `${project.name}/${file}`,
|
||||
type: "file",
|
||||
})),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user