diff --git a/package.json b/package.json index fbdcf85..8dbb69d 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "format": "prettier --cache --write '**/*.{md,json,css,scss,js,mjs,cjs,ts,tsx}'" }, "dependencies": { + "@octokit/rest": "^20.0.2", "@planetscale/database": "^1.11.0", "@t3-oss/env-nextjs": "^0.7.1", "@tanstack/react-query": "^4.36.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index efba2a0..47a7a52 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false dependencies: + '@octokit/rest': + specifier: ^20.0.2 + version: 20.0.2 '@planetscale/database': specifier: ^1.11.0 version: 1.13.0 @@ -753,6 +756,109 @@ packages: fastq: 1.16.0 dev: true + /@octokit/auth-token@4.0.0: + resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} + engines: {node: '>= 18'} + dev: false + + /@octokit/core@5.1.0: + resolution: {integrity: sha512-BDa2VAMLSh3otEiaMJ/3Y36GU4qf6GI+VivQ/P41NC6GHcdxpKlqV0ikSZ5gdQsmS3ojXeRx5vasgNTinF0Q4g==} + engines: {node: '>= 18'} + dependencies: + '@octokit/auth-token': 4.0.0 + '@octokit/graphql': 7.0.2 + '@octokit/request': 8.1.6 + '@octokit/request-error': 5.0.1 + '@octokit/types': 12.4.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.1 + dev: false + + /@octokit/endpoint@9.0.4: + resolution: {integrity: sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==} + engines: {node: '>= 18'} + dependencies: + '@octokit/types': 12.4.0 + universal-user-agent: 6.0.1 + dev: false + + /@octokit/graphql@7.0.2: + resolution: {integrity: sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==} + engines: {node: '>= 18'} + dependencies: + '@octokit/request': 8.1.6 + '@octokit/types': 12.4.0 + universal-user-agent: 6.0.1 + dev: false + + /@octokit/openapi-types@19.1.0: + resolution: {integrity: sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw==} + dev: false + + /@octokit/plugin-paginate-rest@9.1.5(@octokit/core@5.1.0): + resolution: {integrity: sha512-WKTQXxK+bu49qzwv4qKbMMRXej1DU2gq017euWyKVudA6MldaSSQuxtz+vGbhxV4CjxpUxjZu6rM2wfc1FiWVg==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=5' + dependencies: + '@octokit/core': 5.1.0 + '@octokit/types': 12.4.0 + dev: false + + /@octokit/plugin-request-log@4.0.0(@octokit/core@5.1.0): + resolution: {integrity: sha512-2uJI1COtYCq8Z4yNSnM231TgH50bRkheQ9+aH8TnZanB6QilOnx8RMD2qsnamSOXtDj0ilxvevf5fGsBhBBzKA==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=5' + dependencies: + '@octokit/core': 5.1.0 + dev: false + + /@octokit/plugin-rest-endpoint-methods@10.2.0(@octokit/core@5.1.0): + resolution: {integrity: sha512-ePbgBMYtGoRNXDyKGvr9cyHjQ163PbwD0y1MkDJCpkO2YH4OeXX40c4wYHKikHGZcpGPbcRLuy0unPUuafco8Q==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=5' + dependencies: + '@octokit/core': 5.1.0 + '@octokit/types': 12.4.0 + dev: false + + /@octokit/request-error@5.0.1: + resolution: {integrity: sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==} + engines: {node: '>= 18'} + dependencies: + '@octokit/types': 12.4.0 + deprecation: 2.3.1 + once: 1.4.0 + dev: false + + /@octokit/request@8.1.6: + resolution: {integrity: sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==} + engines: {node: '>= 18'} + dependencies: + '@octokit/endpoint': 9.0.4 + '@octokit/request-error': 5.0.1 + '@octokit/types': 12.4.0 + universal-user-agent: 6.0.1 + dev: false + + /@octokit/rest@20.0.2: + resolution: {integrity: sha512-Ux8NDgEraQ/DMAU1PlAohyfBBXDwhnX2j33Z1nJNziqAfHi70PuxkFYIcIt8aIAxtRE7KVuKp8lSR8pA0J5iOQ==} + engines: {node: '>= 18'} + dependencies: + '@octokit/core': 5.1.0 + '@octokit/plugin-paginate-rest': 9.1.5(@octokit/core@5.1.0) + '@octokit/plugin-request-log': 4.0.0(@octokit/core@5.1.0) + '@octokit/plugin-rest-endpoint-methods': 10.2.0(@octokit/core@5.1.0) + dev: false + + /@octokit/types@12.4.0: + resolution: {integrity: sha512-FLWs/AvZllw/AGVs+nJ+ELCDZZJk+kY0zMen118xhL2zD0s1etIUHm1odgjP7epxYU1ln7SZxEUWYop5bhsdgQ==} + dependencies: + '@octokit/openapi-types': 19.1.0 + dev: false + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1250,6 +1356,10 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true + /before-after-hook@2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + dev: false + /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -1480,6 +1590,10 @@ packages: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} + /deprecation@2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dev: false + /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -3069,7 +3183,6 @@ packages: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 - dev: true /optionator@0.9.3: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} @@ -3838,6 +3951,10 @@ packages: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} dev: true + /universal-user-agent@6.0.1: + resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} + dev: false + /update-browserslist-db@1.0.13(browserslist@4.22.2): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true @@ -3955,7 +4072,6 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} diff --git a/src/components/Nvim/NvimTree.tsx b/src/components/Nvim/NvimTree.tsx index def578f..ef617cf 100644 --- a/src/components/Nvim/NvimTree.tsx +++ b/src/components/Nvim/NvimTree.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from "react"; import { useTerminal } from "~/context/TerminalContext"; +import { api } from "~/utils/api"; import { type Cell } from "~/utils/terminal/cell"; import { TerminalRenderer } from "~/utils/terminal/renderer"; import { theme } from "~/utils/terminal/theme"; @@ -45,7 +46,12 @@ type File = { ); const FILES_SRC: Array = [ - { name: "projects", type: "directory", children: [], folded: true }, + { + name: "projects", + type: "directory", + children: [{ name: "README.md", type: "md" }], + folded: true, + }, { name: "README.md", type: "md" }, { name: "LICENSE.md", type: "md" }, { name: "prout", type: "directory", children: [], folded: true }, @@ -54,16 +60,10 @@ const FILES_SRC: Array = [ ]; export const NvimTree = () => { + const { data: repos } = api.github.getRepos.useQuery(); + const [selected, setSelected] = useState(0); - const [files, setFiles] = useState( - FILES_SRC.sort((a, b) => a.name.localeCompare(b.name)).sort((a, b) => - a.type === "directory" && b.type !== "directory" - ? -1 - : a.type !== "directory" && b.type === "directory" - ? 1 - : 0, - ), - ); + const [files, setFiles] = useState(FILES_SRC); const { cols: width, rows: height } = useTerminal(); const canvas = new TerminalRenderer(width * 0.2, height - 2, { @@ -71,6 +71,39 @@ export const NvimTree = () => { }); const tree = new TerminalRenderer(canvas.width - 3, height - 1); + tree.write(0, selected, " ".repeat(tree.width), { background: "#504651" }); + + let y = 0; + let indent = 0; + const renderTree = (files: Array) => { + files.forEach(file => { + tree.apply(2 + indent * 2, y, FILE_STYLES[file.type]); + + if (file.type === "directory") { + tree.apply(indent * 2, y, file.folded ? PATH_FOLDED : PATH_UNFOLDED); + tree.write(4 + indent * 2, y, file.name, { + foreground: FILE_STYLES.directory.foreground, + }); + + y++; + if (!file.folded) { + indent++; + renderTree(file.children); + indent--; + } + } else { + if (file.name === "README.md") { + tree.write(4 + indent * 2, y, file.name, { + foreground: theme.yellow, + fontWeight: 800, + }); + } else { + tree.write(4 + indent * 2, y, file.name); + } + y++; + } + }); + }; useEffect(() => { const onScroll = (event: KeyboardEvent) => { @@ -80,18 +113,36 @@ export const NvimTree = () => { break; case "ArrowDown": - setSelected(x => Math.min(files.length - 1, x + 1)); + setSelected(x => Math.min(y - 1, x + 1)); break; case "Enter": - const newFiles = [...files]; + let y = 0; + const findFile = (files: Array): File | null => { + for (const f of files) { + if (y === selected) { + return f; + } + y++; + if (f.type === "directory" && !f.folded) { + const found = findFile(f.children); + if (found) return found; + } + } - const file = newFiles[selected]; - if (file?.type === "directory") { - file.folded = !file.folded; + return null; + }; + + const current = findFile(files); + if (!current) { + setSelected(0); + return; } - setFiles(newFiles); + if (current.type === "directory") { + current.folded = !current.folded; + setFiles([...files]); + } break; } }; @@ -103,30 +154,19 @@ export const NvimTree = () => { }; }); - tree.write(0, selected, " ".repeat(tree.width), { background: "#504651" }); - - files.forEach((file, y) => { - tree.apply(2, y, FILE_STYLES[file.type]); - - if (file.type === "directory") { - tree.apply(0, y, file.folded ? PATH_FOLDED : PATH_UNFOLDED); - - tree.write(4, y, file.name, { - foreground: FILE_STYLES.directory.foreground, - }); - } else { - if (file.name === "README.md") { - tree.write(4, y, file.name, { - foreground: theme.yellow, - fontWeight: 800, - }); - } else { - tree.write(4, y, file.name); - } - } - }); + renderTree(files); canvas.writeElement(tree, 2, 1); return

{canvas.render()}

; }; + +/* + .sort((a, b) => a.name.localeCompare(b.name)).sort((a, b) => + a.type === "directory" && b.type !== "directory" + ? -1 + : a.type !== "directory" && b.type === "directory" + ? 1 + : 0, + ), +*/ diff --git a/src/server/api/root.ts b/src/server/api/root.ts index d93ffd7..6903a04 100644 --- a/src/server/api/root.ts +++ b/src/server/api/root.ts @@ -1,5 +1,8 @@ import { createTRPCRouter } from "~/server/api/trpc"; +import { github } from "./routers/github"; -export const appRouter = createTRPCRouter({}); +export const appRouter = createTRPCRouter({ + github, +}); export type AppRouter = typeof appRouter; diff --git a/src/server/api/routers/github/getRepos.ts b/src/server/api/routers/github/getRepos.ts new file mode 100644 index 0000000..234a74c --- /dev/null +++ b/src/server/api/routers/github/getRepos.ts @@ -0,0 +1,10 @@ +import { Octokit } from "@octokit/rest"; +import { publicProcedure } from "../../trpc"; + +export const getRepos = publicProcedure.query(async () => { + const octokit = new Octokit(); + + //const response = await octokit.repos.listForUser({ username: "pihkaal" }); + //const repos = response.data.filter(x => x.name !== "pihkaal"); + return []; +}); diff --git a/src/server/api/routers/github/index.ts b/src/server/api/routers/github/index.ts new file mode 100644 index 0000000..28ec58b --- /dev/null +++ b/src/server/api/routers/github/index.ts @@ -0,0 +1,6 @@ +import { createTRPCRouter } from "../../trpc"; +import { getRepos } from "./getRepos"; + +export const github = createTRPCRouter({ + getRepos, +});