mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-11-30 01:44:58 +03:00
Removed UI folder
This commit is contained in:
parent
d4afda7189
commit
6ab2d13a47
@ -1,27 +0,0 @@
|
||||
/* eslint-env node */
|
||||
|
||||
module.exports = {
|
||||
// root: true,
|
||||
// env: { browser: true, es2020: true },
|
||||
// extends: [
|
||||
// 'eslint:recommended',
|
||||
// 'plugin:@typescript-eslint/recommended',
|
||||
// 'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||
// 'plugin:react-hooks/recommended',
|
||||
// ],
|
||||
// parser: '@typescript-eslint/parser',
|
||||
// parserOptions: {
|
||||
// ecmaVersion: 'latest',
|
||||
// sourceType: 'module',
|
||||
// project: true,
|
||||
// tsconfigRootDir: __dirname,
|
||||
// },
|
||||
// plugins: ['react-refresh'],
|
||||
// rules: {
|
||||
// 'react-refresh/only-export-components': [
|
||||
// 'warn',
|
||||
// { allowConstantExport: true },
|
||||
// ],
|
||||
// '@typescript-eslint/no-non-null-assertion': 'off',
|
||||
// },
|
||||
}
|
26
modules/chess/ui/.gitignore
vendored
26
modules/chess/ui/.gitignore
vendored
@ -1,26 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
.env
|
@ -1,3 +0,0 @@
|
||||
# chess-ui
|
||||
|
||||
The UI for the Uqbar chess app. This UI is available at /chess:chess:uqbar/ on any Uqbar node.
|
File diff suppressed because one or more lines are too long
4160
modules/chess/ui/package-lock.json
generated
4160
modules/chess/ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,45 +0,0 @@
|
||||
{
|
||||
"name": "api-maestro-ui",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"start": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"copy": "mkdir -p ../pkg/ui && rm -rf ../pkg/ui/* && cp -r dist/* ../pkg/ui/",
|
||||
"build:copy": "npm run build && npm run copy",
|
||||
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-oauth/google": "^0.11.0",
|
||||
"@types/node-forge": "^1.3.5",
|
||||
"@uqbar/client-encryptor-api": "^0.2.1",
|
||||
"buffer": "^6.0.3",
|
||||
"chess.js": "^1.0.0-beta.6",
|
||||
"moment": "^2.29.4",
|
||||
"node-forge": "^1.3.1",
|
||||
"react": "^18.2.0",
|
||||
"react-chessboard": "^4.2.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.14.1",
|
||||
"zustand": "^4.3.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.4.2",
|
||||
"@types/react": "^18.2.14",
|
||||
"@types/react-dom": "^18.2.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.61.0",
|
||||
"@typescript-eslint/parser": "^5.61.0",
|
||||
"@vitejs/plugin-react": "^4.0.1",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "^8.44.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.1",
|
||||
"postcss": "^8.4.25",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^4.4.0",
|
||||
"vite-plugin-mkcert": "^1.16.0"
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
#root {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||
}
|
||||
|
||||
@keyframes logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
a:nth-of-type(2) .logo {
|
||||
animation: logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
@ -1,239 +0,0 @@
|
||||
import { FormEvent, useCallback, useEffect, useMemo, useState, MouseEvent } from 'react'
|
||||
import { Chess } from "chess.js";
|
||||
import { Chessboard } from "react-chessboard";
|
||||
import UqbarEncryptorApi from '@uqbar/client-encryptor-api'
|
||||
import useChessStore, { Game } from './store';
|
||||
|
||||
declare global {
|
||||
var window: Window & typeof globalThis;
|
||||
var our: { node: string, process: string };
|
||||
}
|
||||
|
||||
import './App.css'
|
||||
|
||||
let inited = false
|
||||
|
||||
interface SelectedGame extends Game {
|
||||
game: Chess
|
||||
}
|
||||
|
||||
const isTurn = (game: Game, node: string) => (game.turns || 0) % 2 === 0 ? node === game.white : node === game.black
|
||||
|
||||
const BASE_URL = import.meta.env.BASE_URL;
|
||||
if (window.our) window.our.process = BASE_URL?.replace("/", "");
|
||||
|
||||
const PROXY_TARGET = `${(import.meta.env.VITE_NODE_URL || "http://localhost:8080")}${BASE_URL}`;
|
||||
|
||||
// This env also has BASE_URL which should match the process + package name
|
||||
const WEBSOCKET_URL = import.meta.env.DEV
|
||||
? `${PROXY_TARGET.replace('http', 'ws')}`
|
||||
: undefined;
|
||||
|
||||
function App() {
|
||||
const { games, handleWsMessage, set } = useChessStore()
|
||||
const [screen, setScreen] = useState('new')
|
||||
const [newGame, setNewGame] = useState('')
|
||||
|
||||
const game: SelectedGame | undefined = useMemo(() => games[screen] ? ({ ...games[screen], game: new Chess(games[screen].board) }) : undefined, [games, screen])
|
||||
const currentTurn = useMemo(() => (game?.turns || 0) % 2 === 0 ? `${game?.white} (white)` : `${game?.black} (black)`, [game])
|
||||
|
||||
useEffect(() => {
|
||||
if (!inited) {
|
||||
inited = true
|
||||
|
||||
new UqbarEncryptorApi({
|
||||
uri: WEBSOCKET_URL,
|
||||
nodeId: window.our.node,
|
||||
processId: window.our.process,
|
||||
onMessage: handleWsMessage
|
||||
});
|
||||
}
|
||||
|
||||
fetch(`${BASE_URL}/games`).then(res => res.json()).then((games) => {
|
||||
set({ games })
|
||||
}).catch(console.error)
|
||||
|
||||
}, []) // eslint-disable-line
|
||||
|
||||
const startNewGame = useCallback(async (e: FormEvent) => {
|
||||
e.preventDefault()
|
||||
try {
|
||||
const createdGame = await fetch(`${BASE_URL}/games`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ id: newGame })
|
||||
}).then(r => {
|
||||
if (r.status === 409) {
|
||||
if (games[newGame]) {
|
||||
setScreen(newGame)
|
||||
} else {
|
||||
alert('Game already exists, please refresh the page and select it.')
|
||||
}
|
||||
throw new Error('Game already exists')
|
||||
} else if (r.status === 503) {
|
||||
alert(`${newGame} may be offline, please confirm it is online and try again.`)
|
||||
throw new Error('Player offline')
|
||||
} else if (r.status === 400) {
|
||||
alert('Please enter a valid player ID')
|
||||
throw new Error('Invalid player ID')
|
||||
} else if (r.status > 399) {
|
||||
alert('There was an error creating the game. Please try again.')
|
||||
throw new Error('Error creating game')
|
||||
}
|
||||
|
||||
return r.json()
|
||||
})
|
||||
|
||||
const allGames = { ...games }
|
||||
allGames[createdGame.id] = createdGame
|
||||
set({ games: allGames })
|
||||
setScreen(newGame)
|
||||
setNewGame('')
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}, [games, newGame, setNewGame, set])
|
||||
|
||||
const onDrop = useCallback((sourceSquare: string, targetSquare: string) => {
|
||||
if (!game || !isTurn(game, window.our.node)) return false
|
||||
|
||||
const move = {
|
||||
from: sourceSquare,
|
||||
to: targetSquare,
|
||||
promotion: "q", // always promote to a queen for example simplicity
|
||||
}
|
||||
const gameCopy = { ...game };
|
||||
const result = gameCopy.game.move(move);
|
||||
|
||||
if (result === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gameCopy.board = gameCopy.game.fen()
|
||||
const allGames = { ...games }
|
||||
allGames[game.id] = gameCopy
|
||||
set({ games: allGames })
|
||||
|
||||
fetch(`${BASE_URL}/games`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ id: game.id, move: sourceSquare + targetSquare })
|
||||
}).then(r => r.json())
|
||||
.then((updatedGame) => {
|
||||
const allGames = { ...games }
|
||||
allGames[game.id] = updatedGame
|
||||
set({ games: allGames })
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
alert('There was an error making your move. Please try again')
|
||||
// reset the board
|
||||
const allGames = { ...games }
|
||||
const gameCopy = { ...game }
|
||||
gameCopy.game.undo()
|
||||
allGames[game.id] = gameCopy
|
||||
set({ games: allGames })
|
||||
})
|
||||
|
||||
return true
|
||||
}, [game, games, set])
|
||||
|
||||
const resignGame = useCallback((e: MouseEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
if (!game) return
|
||||
|
||||
if (!window.confirm('Are you sure you want to resign this game?')) return
|
||||
|
||||
fetch(`${BASE_URL}/games?id=${game.id}`, {
|
||||
method: 'DELETE',
|
||||
}).then(r => r.json())
|
||||
.then((updatedGame) => {
|
||||
const allGames = { ...games }
|
||||
allGames[game.id] = updatedGame
|
||||
set({ games: allGames })
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
alert('There was an error resigning the game. Please try again')
|
||||
})
|
||||
}, [game])
|
||||
|
||||
const rematchGame = useCallback(async (e: MouseEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
if (!game) return
|
||||
|
||||
try {
|
||||
const createdGame = await fetch(`${BASE_URL}/games`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ id: game.id })
|
||||
}).then(r => r.json())
|
||||
|
||||
const allGames = { ...games }
|
||||
allGames[createdGame.id] = createdGame
|
||||
set({ games: allGames })
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
alert('You could not create the game. Please make sure your current game with this player (if any) has ended and try again.')
|
||||
}
|
||||
}, [game])
|
||||
|
||||
return (
|
||||
<div className='flex flex-col justify-center items-center'>
|
||||
<div className='flex flex-col justify-center' style={{ maxHeight: '100vh', maxWidth: '800px', width: '100%', position: 'relative' }}>
|
||||
<a href="/" className='absolute top-6 left-0 m-4' style={{ fontSize: 24, color: 'white' }} onClick={e => { e.preventDefault(); window.history.back() }}>
|
||||
◀ Back
|
||||
</a>
|
||||
<h1 className='m-4'>Chess by Uqbar</h1>
|
||||
<div className='flex flex-row justify-center items-center h-screen border rounded'>
|
||||
{Object.keys(games).length > 0 && <div className='flex flex-col border-r' style={{ width: '25%', height: '100%' }}>
|
||||
<h3 className='m-2'>Games</h3>
|
||||
<button className='bg-green-600 hover:bg-green-800 text-white font-bold py-2 px-4 m-2 rounded' onClick={() => setScreen('new')}>New</button>
|
||||
<div className='flex flex-col overflow-scroll'>
|
||||
{Object.values(games).map(game => (
|
||||
<div key={game?.id} onClick={() => setScreen(game?.id)}
|
||||
className={`game-entry m-2 ${screen !== game?.id && isTurn(game, window.our.node) ? 'is-turn' : ''} ${screen === game?.id ? 'selected' : ''} ${game?.ended ? 'ended' : ''}`}
|
||||
>
|
||||
{game?.id}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>}
|
||||
<div className='flex flex-col justify-center items-center' style={{ width: '75%' }}>
|
||||
{screen === 'new' || !game ? (
|
||||
<>
|
||||
<h2 className='mb-2'>Start New Game</h2>
|
||||
<h4 className='mb-2'>(game creator will be white)</h4>
|
||||
<form onSubmit={startNewGame} className='flex flex-col justify-center mb-40' style={{ maxWidth: 400 }}>
|
||||
<label className='mb-2' style={{ alignSelf: 'flex-start', fontWeight: '600' }}>Player ID</label>
|
||||
<input className='border rounded p-2 mb-2' style={{ color: 'black' }} type='text' placeholder='Player ID' value={newGame} onChange={e => setNewGame(e.target.value)} />
|
||||
<button className='bg-green-600 hover:bg-green-800 text-white font-bold py-2 px-4 rounded' type="submit">Start Game</button>
|
||||
</form>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className='flex flex-row justify-between items-center w-full px-4 pb-2'>
|
||||
<h3>{screen}</h3>
|
||||
<h4>{game?.ended ? 'Game Ended' : `Turn: ${currentTurn}`}</h4>
|
||||
{game?.ended ? (
|
||||
<button className='bg-green-600 hover:bg-green-800 text-white font-bold py-1 px-4 rounded' onClick={rematchGame}>Rematch</button>
|
||||
) : (
|
||||
<button className='bg-green-600 hover:bg-green-800 text-white font-bold py-1 px-4 rounded' onClick={resignGame}>Resign</button>
|
||||
)}
|
||||
</div>
|
||||
<Chessboard position={game?.game.fen()} onPieceDrop={onDrop} boardOrientation={game?.white === window.our.node ? 'white' : 'black'} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
@ -1,152 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
width: 100%;
|
||||
|
||||
--uq-vlightpurple: #d9dcfc;
|
||||
--uq-lightpurple: #c7cafa;
|
||||
--uq-purple: #727bf2;
|
||||
--uq-darkpurple: #5761ef;
|
||||
--midnightpurp: #0a1170;
|
||||
--forgottenpurp: #45475e;
|
||||
--uq-lightpink: #f3ced2;
|
||||
--uq-pink: #dd7c8a;
|
||||
--uq-darkpink: #cd3c52;
|
||||
--blush: #d55d6f;
|
||||
--celeste: #adebe5;
|
||||
--lturq: #6bdbd0;
|
||||
--turq: #3acfc0;
|
||||
--celadon: #21897e;
|
||||
--deep-jungle: #14524c;
|
||||
--old-mint: #659792;
|
||||
--washed-gray: rgba(0, 0, 0, 0.03);
|
||||
--light-gray: rgba(0, 0, 0, 0.1);
|
||||
--medium-gray: rgba(0, 0, 0, 0.2);
|
||||
--dark-gray: rgba(0, 0, 0, 0.5);
|
||||
--charcoal: #333;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
/* place-items: center; */
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
color: white;
|
||||
background-color: var(--midnightpurp);
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
@keyframes colorChange {
|
||||
0%, 100% {
|
||||
background-color: var(--uq-purple); /* Start and end color */
|
||||
}
|
||||
50% {
|
||||
background-color: var(--uq-pink); /* 2nd rhythmic change */
|
||||
}
|
||||
}
|
||||
|
||||
.game-entry {
|
||||
width: calc(100% - 1em);
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
background-color: var(--uq-purple);
|
||||
padding: 0.5em;
|
||||
border-radius: 0.25em;
|
||||
}
|
||||
|
||||
.game-entry.is-turn {
|
||||
animation: colorChange 3s infinite;
|
||||
}
|
||||
|
||||
.game-entry.selected {
|
||||
background-color: var(--uq-darkpink);
|
||||
}
|
||||
|
||||
.game-entry.is-ended {
|
||||
background-color: lightgray;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.game-entry:hover {
|
||||
background-color: var(--uq-pink);
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import './index.css'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
)
|
@ -1,50 +0,0 @@
|
||||
import { create } from 'zustand'
|
||||
import { persist, createJSONStorage } from 'zustand/middleware'
|
||||
|
||||
export interface Game {
|
||||
id: string,
|
||||
turns: number,
|
||||
board: string, // FEN format of the board
|
||||
white: string,
|
||||
black: string,
|
||||
ended: boolean,
|
||||
}
|
||||
|
||||
export interface Games {
|
||||
[id: string]: Game
|
||||
}
|
||||
|
||||
export interface ChessStore {
|
||||
games: Games
|
||||
handleWsMessage: (message: string) => void
|
||||
set: (partial: ChessStore | Partial<ChessStore>) => void
|
||||
}
|
||||
|
||||
type WsMessage = { kind: 'game_update', data: Game }
|
||||
|
||||
const useChessStore = create<ChessStore>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
games: {},
|
||||
handleWsMessage: (json: string) => {
|
||||
try {
|
||||
const { kind, data } = JSON.parse(json) as WsMessage
|
||||
console.log(kind, data)
|
||||
|
||||
if (kind === 'game_update') {
|
||||
set({ games: { ...get().games, [data.id]: data } })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error parsing WebSocket message", error);
|
||||
}
|
||||
},
|
||||
set,
|
||||
}),
|
||||
{
|
||||
name: 'chess', // unique name
|
||||
storage: createJSONStorage(() => localStorage), // (optional) by default, 'localStorage' is used
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
export default useChessStore
|
@ -1,5 +0,0 @@
|
||||
export const genFetchRoute = (route: string) => {
|
||||
return window.location.pathname.includes('/http-proxy/serve/') ?
|
||||
`/http-proxy/serve/${window.location.pathname.split('/')[3]}/${route}`:
|
||||
route
|
||||
}
|
1
modules/chess/ui/src/vite-env.d.ts
vendored
1
modules/chess/ui/src/vite-env.d.ts
vendored
@ -1 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
@ -1,11 +0,0 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{js,ts,jsx,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if there are enough parameters provided.
|
||||
if [ "$#" -ne 4 ]; then
|
||||
echo "Usage: $0 <url> <node-id> <vfs-identifier> <destination_process>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
URL="$1"
|
||||
NODE="$2"
|
||||
IDENTIFIER="$3"
|
||||
DEST_PROC="$4"
|
||||
|
||||
# Generate new vfs capabilities and give "read" to the destination process
|
||||
curl "$URL/rpc/message" -H 'content-type: application/json' -d "{\"node\": \"$NODE\", \"process\": \"vfs\", \"inherit\": false, \"expects_response\": false, \"ipc\": \"{\\\"New\\\": {\\\"identifier\\\": \\\"$IDENTIFIER\\\"}}\", \"metadata\": null, \"context\": null, \"mime\": null, \"data\": null}"
|
||||
curl "$URL/rpc/capabilities/transfer" -H 'content-type: application/json' -d "{\"destination_node\": \"$NODE\", \"destination_process\": \"$DEST_PROC\", \"node\": \"$NODE\", \"process\": \"vfs\", \"params\": \"{\\\"identifier\\\": \\\"$IDENTIFIER\\\",\\\"kind\\\":\\\"read\\\"}\"}"
|
@ -1,30 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if there are enough parameters provided.
|
||||
if [ "$#" -ne 5 ]; then
|
||||
echo "Usage: $0 <url> <node-id> <vfs-identifier> <index.html> <assets directory>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
URL="$1"
|
||||
NODE="$2"
|
||||
IDENTIFIER="$3"
|
||||
INDEX_HTML="$4"
|
||||
DIRECTORY="$5"
|
||||
|
||||
# Upload index.html
|
||||
curl "$URL/rpc/message" -H 'content-type: application/json' -d "{\"node\": \"$NODE\", \"process\": \"vfs\", \"inherit\": false, \"expects_response\": false, \"ipc\": \"{\\\"Add\\\": {\\\"identifier\\\": \\\"$IDENTIFIER\\\", \\\"full_path\\\": \\\"/index.html\\\", \\\"entry_type\\\": {\\\"NewFile\\\": null}}}\", \"metadata\": null, \"context\": null, \"mime\": null, \"data\": \"$(base64 < $INDEX_HTML)\"}"
|
||||
|
||||
[[ "$DIRECTORY" != */ ]] && DIRECTORY="$DIRECTORY/"
|
||||
|
||||
# Iterate over files in the specified directory
|
||||
for FILE in "$DIRECTORY"*; do
|
||||
# Check if it's a regular file before proceeding
|
||||
if [[ -f "$FILE" ]]; then
|
||||
# Extract just the file name
|
||||
FILE_NAME=$(basename "$FILE")
|
||||
|
||||
# upload file to Uqbar VFS
|
||||
curl "$URL/rpc/message" -H 'content-type: application/json' -d "{\"node\": \"$NODE\", \"process\": \"vfs\", \"inherit\": false, \"expects_response\": false, \"ipc\": \"{\\\"Add\\\": {\\\"identifier\\\": \\\"$IDENTIFIER\\\", \\\"full_path\\\": \\\"/$FILE_NAME\\\", \\\"entry_type\\\": {\\\"NewFile\\\": null}}}\", \"metadata\": null, \"context\": null, \"mime\": null, \"data\": \"$(base64 < "$FILE")\"}"
|
||||
fi
|
||||
done
|
@ -1,67 +0,0 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
/*
|
||||
If you are developing a UI outside of an Uqbar project,
|
||||
comment out the following 2 lines:
|
||||
*/
|
||||
import manifest from '../pkg/manifest.json'
|
||||
import metadata from '../pkg/metadata.json'
|
||||
|
||||
/*
|
||||
IMPORTANT:
|
||||
This must match the process name from pkg/manifest.json + pkg/metadata.json
|
||||
The format is "/" + "process_name:package_name:publisher_node"
|
||||
*/
|
||||
const BASE_URL = `/${manifest[0].process_name}:${metadata.package}:${metadata.publisher}`;
|
||||
|
||||
// This is the proxy URL, it must match the node you are developing against
|
||||
const PROXY_URL = (process.env.VITE_NODE_URL || 'http://127.0.0.1:8080').replace('localhost', '127.0.0.1');
|
||||
|
||||
console.log('process.env.VITE_NODE_URL', process.env.VITE_NODE_URL, PROXY_URL);
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
base: BASE_URL,
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: ['/our.js']
|
||||
}
|
||||
},
|
||||
server: {
|
||||
open: true,
|
||||
proxy: {
|
||||
'/our': {
|
||||
target: PROXY_URL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
[`${BASE_URL}/our.js`]: {
|
||||
target: PROXY_URL,
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(BASE_URL, ''),
|
||||
},
|
||||
// This route will match all other HTTP requests to the backend
|
||||
[`^${BASE_URL}/(?!(@vite/client|src/.*|node_modules/.*|@react-refresh|$))`]: {
|
||||
target: PROXY_URL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
// '/example': {
|
||||
// target: PROXY_URL,
|
||||
// changeOrigin: true,
|
||||
// rewrite: (path) => path.replace(BASE_URL, ''),
|
||||
// // This is only for debugging purposes
|
||||
// configure: (proxy, _options) => {
|
||||
// proxy.on('error', (err, _req, _res) => {
|
||||
// console.log('proxy error', err);
|
||||
// });
|
||||
// proxy.on('proxyReq', (proxyReq, req, _res) => {
|
||||
// console.log('Sending Request to the Target:', req.method, req.url);
|
||||
// });
|
||||
// proxy.on('proxyRes', (proxyRes, req, _res) => {
|
||||
// console.log('Received Response from the Target:', proxyRes.statusCode, req.url);
|
||||
// });
|
||||
// },
|
||||
// },
|
||||
}
|
||||
}
|
||||
});
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user