Skip to content

Commit d8529e5

Browse files
authored
Experimental Explore Project (#96)
* New Explore App * Configurable API * Routes and format * Explore app wip * Basic explorer working * API only on gateways, allow disabling * Fix build * API progress * Fix entity API for comments * Explore capabilities, comments, citations, changes
1 parent b4ec0d3 commit d8529e5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+3049
-698
lines changed

frontend/apps/explore/.env

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
VITE_PUBLIC_EXPLORE_API_HOST=http://localhost:3000

frontend/apps/explore/.gitignore

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

frontend/apps/explore/README.md

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Hypermedia Explorer
2+
3+
Browse the data on the Hypermedia network
4+
5+
## Development
6+
7+
### Prerequisites
8+
9+
- Node.js (v16+)
10+
- Yarn
11+
12+
### Setup
13+
14+
1. Install dependencies:
15+
16+
```bash
17+
yarn install
18+
```
19+
20+
2. Start the development server:
21+
22+
```bash
23+
yarn dev
24+
```
25+
26+
3. Build for production:
27+
```bash
28+
yarn build
29+
```
30+
31+
## Environment Variables
32+
33+
The app uses the following environment variables:
34+
35+
- `VITE_PUBLIC_EXPLORE_API_HOST`: The default API host URL (defaults to http://localhost:3000)
36+
37+
You can customize these by creating a `.env` file in the root directory.
38+
39+
## Settings
40+
41+
The app includes a settings panel accessible via the gear icon in the lower left corner. You can configure:
42+
43+
- Explore API Host: The URL of the API server
44+
45+
```
46+
cd frontend/apps/explore
47+
yarn
48+
yarn dev
49+
```
50+
51+
## Deploy
52+
53+
```
54+
cd frontend/apps/explore
55+
yarn
56+
yarn build
57+
# the build is in frontend/apps/explore/dist
58+
```
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import js from '@eslint/js'
2+
import globals from 'globals'
3+
import reactHooks from 'eslint-plugin-react-hooks'
4+
import reactRefresh from 'eslint-plugin-react-refresh'
5+
import tseslint from 'typescript-eslint'
6+
7+
export default tseslint.config(
8+
{ ignores: ['dist'] },
9+
{
10+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
11+
files: ['**/*.{ts,tsx}'],
12+
languageOptions: {
13+
ecmaVersion: 2020,
14+
globals: globals.browser,
15+
},
16+
plugins: {
17+
'react-hooks': reactHooks,
18+
'react-refresh': reactRefresh,
19+
},
20+
rules: {
21+
...reactHooks.configs.recommended.rules,
22+
'react-refresh/only-export-components': [
23+
'warn',
24+
{ allowConstantExport: true },
25+
],
26+
},
27+
},
28+
)

frontend/apps/explore/index.html

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Hypermedia Explorer</title>
7+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
8+
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
9+
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
10+
<link rel="manifest" href="/site.webmanifest" />
11+
</head>
12+
<body>
13+
<div id="root"></div>
14+
<script type="module" src="/src/main.tsx"></script>
15+
</body>
16+
</html>

frontend/apps/explore/package.json

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "@shm/explore",
3+
"private": true,
4+
"version": "0.1.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "vite build",
9+
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"@shm/shared": "*",
14+
"@tanstack/react-query": "^5.74.4",
15+
"lucide-react": "^0.358.0",
16+
"react": "^18.2.0",
17+
"react-dom": "^18.2.0",
18+
"react-router-dom": "^7.5.1"
19+
},
20+
"devDependencies": {
21+
"@types/react": "^18.2.56",
22+
"@types/react-dom": "^18.2.19",
23+
"@typescript-eslint/eslint-plugin": "^7.0.2",
24+
"@typescript-eslint/parser": "^7.0.2",
25+
"@vitejs/plugin-react": "^4.2.1",
26+
"autoprefixer": "^10.4.17",
27+
"eslint": "^8.56.0",
28+
"eslint-plugin-react-hooks": "^4.6.0",
29+
"eslint-plugin-react-refresh": "^0.4.5",
30+
"postcss": "^8.4.35",
31+
"tailwindcss": "^3.4.1",
32+
"typescript": "^5.2.2",
33+
"vite": "^5.1.4"
34+
}
35+
}
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
};
Loading
Loading
Loading
545 Bytes
Loading
1.22 KB
Loading
15 KB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "Hypermedia Explorer",
3+
"short_name": "Hypermedia Explorer",
4+
"icons": [
5+
{
6+
"src": "/android-chrome-192x192.png",
7+
"sizes": "192x192",
8+
"type": "image/png"
9+
},
10+
{
11+
"src": "/android-chrome-512x512.png",
12+
"sizes": "512x512",
13+
"type": "image/png"
14+
}
15+
],
16+
"theme_color": "#ffffff",
17+
"background_color": "#ffffff",
18+
"display": "standalone"
19+
}

frontend/apps/explore/public/vite.svg

+1
Loading

frontend/apps/explore/src/App.tsx

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {Route, Routes} from "react-router-dom";
2+
import HM from "./components/HM";
3+
import Home from "./components/Home";
4+
import IPFS from "./components/IPFS";
5+
import Layout from "./components/Layout";
6+
import List from "./components/List";
7+
import Settings from "./components/Settings";
8+
9+
function App() {
10+
return (
11+
<>
12+
<Routes>
13+
<Route element={<Layout />}>
14+
<Route path="/list" element={<List />} />
15+
<Route path="/" element={<Home />} />
16+
<Route path="/hm/*" element={<HM />} />
17+
<Route path="/ipfs/:cid" element={<IPFS />} />
18+
</Route>
19+
</Routes>
20+
<Settings />
21+
</>
22+
);
23+
}
24+
25+
export default App;
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {useSyncExternalStore} from "react";
2+
import {getApiHost, setApiHost} from "./queryClient";
3+
4+
let currentApiHost = getApiHost();
5+
const listeners = new Set<() => void>();
6+
7+
export function subscribe(listener: () => void) {
8+
listeners.add(listener);
9+
return () => {
10+
listeners.delete(listener);
11+
};
12+
}
13+
14+
export function getSnapshot() {
15+
return currentApiHost;
16+
}
17+
18+
export function useApiHost() {
19+
return useSyncExternalStore(subscribe, getSnapshot);
20+
}
21+
22+
export function updateApiHost(newHost: string) {
23+
currentApiHost = newHost;
24+
setApiHost(newHost);
25+
listeners.forEach((listener) => listener());
26+
}
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from "react";
2+
import {FiCopy} from "react-icons/fi";
3+
4+
interface CopyTextButtonProps {
5+
text: string;
6+
}
7+
8+
export const CopyTextButton: React.FC<CopyTextButtonProps> = ({text}) => {
9+
const handleCopy = () => {
10+
navigator.clipboard.writeText(text);
11+
};
12+
13+
return (
14+
<button
15+
onClick={handleCopy}
16+
className="p-2 ml-2 text-gray-500 transition-colors hover:text-gray-700"
17+
title="Copy to clipboard"
18+
>
19+
<FiCopy />
20+
</button>
21+
);
22+
};

0 commit comments

Comments
 (0)