Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ jobs:
# build or types in ways only that full toolchain would catch.
ui:
- 'apps/gittensory-ui/**'
- 'apps/gittensory-miner-ui/**'
- 'apps/gittensory-extension/**'
- 'scripts/build-extension.mjs'
- 'package.json'
Expand Down
1 change: 1 addition & 0 deletions apps/gittensory-miner-ui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/
6 changes: 6 additions & 0 deletions apps/gittensory-miner-ui/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"semi": true,
"singleQuote": false,
"trailingComma": "all",
"printWidth": 120
}
11 changes: 11 additions & 0 deletions apps/gittensory-miner-ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Gittensory Miner UI

Local, read-only dashboard shell for a laptop or fleet miner instance. It mirrors the main
`apps/gittensory-ui/` tooling versions (React 19, TanStack Router, Vite, Tailwind v4) but intentionally
does **not** adopt that app's Cloudflare Worker deploy model or `@lovable.dev/*` scaffold dependency.

The miner package invariant is client-side only with no required phone-home to boot
(`packages/gittensory-miner/DEPLOYMENT.md`). This app is a plain Vite dev server / static build that a
local miner CLI can serve later — not a Wrangler deploy target.

Phase 6 data views (run history, portfolio cards) land in follow-up issues after this empty shell.
28 changes: 28 additions & 0 deletions apps/gittensory-miner-ui/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import js from "@eslint/js";
import eslintPluginPrettier from "eslint-plugin-prettier/recommended";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";

export default tseslint.config(
{ ignores: ["dist", "src/routeTree.gen.ts"] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
"@typescript-eslint/no-unused-vars": "off",
},
},
eslintPluginPrettier,
);
12 changes: 12 additions & 0 deletions apps/gittensory-miner-ui/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Gittensory Miner</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
45 changes: 45 additions & 0 deletions apps/gittensory-miner-ui/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "@jsonbored/gittensory-miner-ui",
"version": "0.0.0",
"private": true,
"description": "Local read-only dashboard shell for the Gittensory miner.",
"packageManager": "npm@10.9.8",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit",
"lint": "eslint .",
"test": "vitest run",
"format": "prettier --write ."
},
"dependencies": {
"@tailwindcss/vite": "^4.3.2",
"@tanstack/react-router": "^1.170.17",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"tailwindcss": "^4.3.2",
"vite-tsconfig-paths": "^6.1.1"
},
"devDependencies": {
"@eslint/js": "^9.39.4",
"@tanstack/router-plugin": "^1.168.19",
"@testing-library/dom": "^10.4.1",
"@testing-library/react": "^16.3.2",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.4",
"eslint": "^9.39.4",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.4.0",
"jsdom": "^28.1.0",
"prettier": "^3.8.1",
"typescript": "^5.9.3",
"typescript-eslint": "^8.56.1",
"vite": "^7.3.1",
"vitest": "^4.1.9"
}
}
12 changes: 12 additions & 0 deletions apps/gittensory-miner-ui/src/app.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";

import { IndexPage } from "./routes/index";

describe("miner ui shell", () => {
it("renders the empty dashboard overview copy", () => {
render(<IndexPage />);
expect(screen.getByRole("heading", { name: "Dashboard shell ready" })).toBeTruthy();
expect(screen.getByText(/Run-history and portfolio views/i)).toBeTruthy();
});
});
20 changes: 20 additions & 0 deletions apps/gittensory-miner-ui/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { RouterProvider, createRouter } from "@tanstack/react-router";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import { routeTree } from "./routeTree.gen";
import "./styles.css";

const router = createRouter({ routeTree });

declare module "@tanstack/react-router" {
interface Register {
router: typeof router;
}
}

createRoot(document.getElementById("root")!).render(
<StrictMode>
<RouterProvider router={router} />
</StrictMode>,
);
57 changes: 57 additions & 0 deletions apps/gittensory-miner-ui/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* eslint-disable */

// @ts-nocheck

// noinspection JSUnusedGlobalSymbols

// This file was automatically generated by TanStack Router.
// You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.

import { Route as rootRouteImport } from "./routes/__root";
import { Route as IndexRouteImport } from "./routes/index";

const IndexRoute = IndexRouteImport.update({
id: "/",
path: "/",
getParentRoute: () => rootRouteImport,
} as any);

export interface FileRoutesByFullPath {
"/": typeof IndexRoute;
}
export interface FileRoutesByTo {
"/": typeof IndexRoute;
}
export interface FileRoutesById {
__root__: typeof rootRouteImport;
"/": typeof IndexRoute;
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath;
fullPaths: "/";
fileRoutesByTo: FileRoutesByTo;
to: "/";
id: "__root__" | "/";
fileRoutesById: FileRoutesById;
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute;
}

declare module "@tanstack/react-router" {
interface FileRoutesByPath {
"/": {
id: "/";
path: "/";
fullPath: "/";
preLoaderRoute: typeof IndexRouteImport;
parentRoute: typeof rootRouteImport;
};
}
}

const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
};
export const routeTree = rootRouteImport._addFileChildren(rootRouteChildren)._addFileTypes<FileRouteTypes>();
28 changes: 28 additions & 0 deletions apps/gittensory-miner-ui/src/routes/__root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Outlet, createRootRoute, Link } from "@tanstack/react-router";

export const Route = createRootRoute({
component: RootLayout,
});

function RootLayout() {
return (
<div className="min-h-screen">
<header className="border-b border-white/10 px-6 py-4">
<div className="mx-auto flex max-w-5xl items-center justify-between gap-4">
<div>
<p className="text-sm uppercase tracking-[0.2em] text-emerald-300/80">Gittensory Miner</p>
<h1 className="text-lg font-semibold">Local dashboard shell</h1>
</div>
<nav className="text-sm text-white/70">
<Link to="/" className="hover:text-white">
Overview
</Link>
</nav>
</div>
</header>
<main className="mx-auto max-w-5xl px-6 py-8">
<Outlet />
</main>
</div>
);
}
17 changes: 17 additions & 0 deletions apps/gittensory-miner-ui/src/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/")({
component: IndexPage,
});

export function IndexPage() {
return (
<section className="rounded-xl border border-white/10 bg-white/5 p-6">
<h2 className="text-xl font-semibold">Dashboard shell ready</h2>
<p className="mt-3 max-w-2xl text-sm leading-6 text-white/70">
This package is the empty Phase 6 scaffold for a local, read-only miner dashboard. Run-history and portfolio
views will mount here in follow-up issues once the local data-access layer is wired.
</p>
</section>
);
}
17 changes: 17 additions & 0 deletions apps/gittensory-miner-ui/src/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@import "tailwindcss";

:root {
color-scheme: dark;
font-family:
"Segoe UI",
system-ui,
-apple-system,
sans-serif;
background: #0f1117;
color: #f4f7f5;
}

body {
margin: 0;
min-height: 100vh;
}
25 changes: 25 additions & 0 deletions apps/gittensory-miner-ui/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"include": ["src/**/*.ts", "src/**/*.tsx", "eslint.config.js"],
"compilerOptions": {
"target": "ES2022",
"jsx": "react-jsx",
"module": "ESNext",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"types": ["vite/client"],

"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": false,
"noEmit": true,

"skipLibCheck": true,
"strict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"paths": {
"@/*": ["./src/*"]
}
}
}
19 changes: 19 additions & 0 deletions apps/gittensory-miner-ui/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import tailwindcss from "@tailwindcss/vite";
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
plugins: [TanStackRouterVite({ target: "react", autoCodeSplitting: true }), react(), tailwindcss(), tsconfigPaths()],
server: {
// Offset from gittensory-ui (5173) so both apps can run side-by-side locally.
port: 5174,
strictPort: true,
},
preview: {
// Offset from gittensory-ui preview (4173).
port: 4174,
strictPort: true,
},
});
12 changes: 12 additions & 0 deletions apps/gittensory-miner-ui/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
import { defineConfig } from "vitest/config";

export default defineConfig({
plugins: [react(), tsconfigPaths()],
test: {
environment: "jsdom",
globals: true,
include: ["src/**/*.test.{ts,tsx}"],
},
});
Loading
Loading