Skip to content

Commit 57ae370

Browse files
committed
Deno Deploy and some small changes
1 parent 233957d commit 57ae370

22 files changed

+1030
-2804
lines changed

.github/copilot-instructions.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# RadixVerse - AI Coding Agent Instructions
2+
3+
## Project Overview
4+
**RadixVerse** is an interactive React + TypeScript web application for exploring alternative number systems and bases. It allows users to visualize and convert numbers across 6 distinct mathematical systems (standard, bijective, balanced, clock, sum, balsum) with support for radixes 2-35.
5+
6+
## Architecture
7+
8+
### Core System: Number Systems (src/utils.ts)
9+
The heart of the app is the `Radix` type - a configuration object for each number system that encodes:
10+
- Character set mapping (0-9, A-Z, or Unicode symbols like ➒, 🅩)
11+
- Low/high value ranges for each system
12+
- Conversion functions: `num2str()` (number→string), `str2num()` (string→number)
13+
14+
**Key insight:** Each radix system has different arithmetic rules:
15+
- **Standard**: 0 to radix-1 (normal base conversion)
16+
- **Bijective**: 1 to radix (no zero; uses only 1 character)
17+
- **Balanced**: Negative to positive around zero (e.g., base-3 balanced uses -1,0,1)
18+
- **Clock**: Symmetric around zero with negative representation (used for hour-like notation)
19+
- **Sum**: Positional system using addition instead of multiplication (powers of r as multipliers)
20+
- **Balsum**: Hybrid balanced+sum system
21+
22+
### UI Component Hierarchy
23+
```
24+
App (src/app.tsx)
25+
├── Router + useStore (manages radixes, enabled radixes, value from URL params)
26+
├── Header (radix editor)
27+
├── Tabs navigation
28+
└── Route components (Show, Add, Multiply, Convert)
29+
└── Table/Tables (src/components/Table.tsx)
30+
└── renderValue (color coding by HSL hue based on value range)
31+
```
32+
33+
**Key pattern:** All route components receive `enabledRadixes` and generate table data locally via `computeProps()` - the app doesn't use global state management.
34+
35+
### Data Persistence
36+
- **localStorage** keys: `theme`, `chars`, `radixes`
37+
- **URL parameters**: `?r=base2&r=base10&value=42&radix=base10` preserves state across sessions
38+
- Error handling: JSON parse failures in localStorage fallback silently and trigger error toast
39+
40+
## Development Workflows
41+
42+
### Build & Serve
43+
```bash
44+
npm start # Vite dev server on port 10000 with HMR
45+
npm run build # Production build with sourcemaps (vite build)
46+
npm run preview # Serve production build on port 10000
47+
npm run check # TypeScript type checking (strict mode)
48+
npm run lint # ESLint on src/ with styled eslint-plugin
49+
npm test # Node native test runner (src/**/*.test.ts)
50+
npm run pre-commit # Check + Lint + Test + Build (CI equivalent)
51+
```
52+
53+
**Pre-commit hook equivalent:** Use `npm run pre-commit` before pushing.
54+
55+
### Quality Standards
56+
- **TypeScript**: Strict mode enabled; ESNext target; JSX via React 19 compiler
57+
- **Linting**: ESLint 9 with @stylistic/eslint-plugin; Biome parser for CSS with Tailwind directives
58+
- **Testing**: Native Node.js test runner (src/**/*.test.ts); example in src/utils.test.ts
59+
- **Styling**: TailwindCSS v4 with DaisyUI components; source in src/app.css
60+
61+
## Key Conventions
62+
63+
### Number Conversion Pattern
64+
**Always use BigInt for arithmetic** - the Radix type stores values as `bigint` because JavaScript's `Number` overflows above 2^53.
65+
66+
```typescript
67+
// ✓ Correct: Handle conversion via Radix methods
68+
const num: bigint = 42n;
69+
const str = num2str(num, radix);
70+
const back: bigint = str2num(str, radix);
71+
72+
// ✗ Avoid: Direct number operations with large values
73+
const val = 999999999999999999; // Loses precision
74+
```
75+
76+
### Component Props Pattern
77+
Route components (Add, Multiply, Convert) receive `radixes: Radix[]` and compute derived state locally:
78+
79+
```typescript
80+
const [ props, setProps ] = useState(computeProps(radix));
81+
useEffect(() => setProps(computeProps(radix, columns, rows)), [ radix, columns, rows ]);
82+
```
83+
84+
This avoids prop drilling and keeps table layout computation close to rendering.
85+
86+
### Error Handling
87+
- **Parser errors**: Catch, log, and call `updateError()` to show toast (10s auto-dismiss)
88+
- **Invalid input**: Sanitize via `sanitizeInput()` and throw with `allowedCharaters(radix)` message
89+
- **Missing radix in URL**: Throw error with helpful context (currently checked in app.tsx)
90+
91+
### localStorage Serialization
92+
Only serialize safe fields (name, radix, system, chars, enabled) - omit Maps and computed fields:
93+
94+
```typescript
95+
const rs = radixes.map(r => ({
96+
name: r.name,
97+
radix: Number(r.radix), // BigInt → Number for JSON
98+
system: r.system,
99+
chars: r.chars,
100+
enabled: r.enabled
101+
}));
102+
```
103+
104+
Deserialization reconstructs Maps via `createRadix()`.
105+
106+
## Integration Points
107+
108+
### Radix Creation
109+
- `createRadixes(chars)` - generates all 35 radixes (radix 2-36) with default enabled set
110+
- `createRadix(num, system, chars, enabled, name)` - single radix with validation
111+
- **Validation**: System+radix combos have constraints (balanced/sum must be odd, clock even)
112+
113+
### Character Sets
114+
- Default: 71-char balanced set (`baseBal71`) = -26 to 26 (Unicode symbols) + 0 + 1-9 + A-Z
115+
- Custom: Set via `setCharsLS()`, retrieved for Radix creation
116+
- **Constraint**: Custom char sets must have odd length and ≥ 71 chars for default radixes
117+
118+
### URL State Recovery
119+
App.tsx `useEffect` runs once to:
120+
1. Detect `?clear-settings` → wipe localStorage
121+
2. Parse `?r=...` params → set enabled radixes
122+
3. Parse `?radix=...` → set working radix
123+
4. Parse `?value=...` → set initial number for conversion
124+
125+
**Order matters:** Radix must be set before parsing value to avoid "Unknown radix" errors.
126+
127+
## Testing & Debugging
128+
129+
### Test Utils
130+
- `src/utils.test.ts` - examples of num2str, str2num, edge cases
131+
- **NaN handling**: `renderValue()` returns empty span for NaN values
132+
133+
### Common Issues
134+
- **Color encoding**: HSL hue = `(val - low) / space * 300` (maps range to 300° color wheel)
135+
- **Table dimensions**: `columns = high - low + 1`; `rows = columns + (bijective ? 1 : 0)`
136+
- **Overflow**: Use `Number.isNaN()` to detect overflow before rendering
137+
138+
## File Reference
139+
- [src/utils.ts](../src/utils.ts) - All number system logic, serialization
140+
- [src/app.tsx](../src/app.tsx) - Router, URL params, useStore hook
141+
- [src/components/Table.tsx](../src/components/Table.tsx) - Rendering logic, color mapping
142+
- [src/components/Show.tsx](../src/components/Show.tsx) - Example of `computeProps()` pattern
143+
- [vite.config.ts](../vite.config.ts) - PWA plugin, React compiler, Tailwind
144+
- [biome.json](../biome.json) - Linter rules (ESNext, no exhaustive deps, allow non-null assertions)

.github/workflows/deploy-deno.yml

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
name: Deploy to Deno Deploy
2+
23
on:
34
push:
45
branches: [ main ]
@@ -15,28 +16,22 @@ jobs:
1516
contents: read # Needed to clone the repository
1617

1718
steps:
18-
- name: Clone repository
19+
- name: Checkout
1920
uses: actions/checkout@v4
2021

21-
- name: Install Deno
22+
- name: Setup Runtime
2223
uses: denoland/setup-deno@v2
2324
with:
2425
deno-version: v2.x
2526

26-
- name: Install Node.js
27-
uses: actions/setup-node@v4
28-
with:
29-
node-version: lts/*
30-
31-
- name: Install step
32-
run: "deno install"
27+
- name: Install dependencies
28+
run: deno install
3329

34-
- name: Build step
35-
run: "deno task build"
30+
- name: Build
31+
run: deno task build
3632

37-
- name: Upload to Deno Deploy
33+
- name: Upload
3834
uses: denoland/deployctl@v1
3935
with:
40-
project: "radixverse"
41-
entrypoint: "dist"
42-
root: "dist"
36+
project: radixverse
37+
entrypoint: deno-deploy-serve.ts

.github/workflows/deploy-fleek.yaml

Lines changed: 0 additions & 32 deletions
This file was deleted.

.github/workflows/deploy-pages.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ on:
66
pull_request:
77
branches: [ main ]
88

9-
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
109
permissions:
1110
pages: write
1211
id-token: write
@@ -52,7 +51,7 @@ jobs:
5251
- name: Upload Pages Artifact
5352
uses: actions/upload-pages-artifact@v4
5453
with:
55-
path: './dist'
54+
path: ./dist
5655

5756
- name: Deploy to Pages
5857
uses: actions/deploy-pages@v4

.vscode/settings.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
{
2-
"[typescript]": { "editor.defaultFormatter": "denoland.vscode-deno" },
3-
"deno.enable": false,
2+
"deno.enable": true,
43
"deno.lint": true,
54
"typescript.tsdk": "node_modules/typescript/lib",
6-
"yaml.schemas": {
7-
"https://json.schemastore.org/github-workflow.json": "file:///Users/kuchta/Projects/radixverse/.github/workflows/deploy.yml"
8-
},
95
"editor.formatOnSaveMode": "modificationsIfAvailable",
106
"typescript.tsserver.experimental.enableProjectDiagnostics": false
117
}

biome.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"files": {
3+
"includes": [
4+
"src/**/*.js",
5+
"src/**/*.ts",
6+
"src/**/*.jsx",
7+
"src/**/*.tsx",
8+
"src/**/*.css"
9+
]
10+
},
11+
"css": {
12+
"parser": {
13+
"tailwindDirectives": true
14+
}
15+
},
16+
"linter": {
17+
"rules": {
18+
"correctness": {
19+
"useExhaustiveDependencies": "off"
20+
},
21+
"style": {
22+
"noNonNullAssertion": "off"
23+
},
24+
"suspicious": {
25+
"noAssignInExpressions": "off",
26+
"noShadowRestrictedNames": "off"
27+
},
28+
"a11y": {
29+
"useButtonType": "off",
30+
"noNoninteractiveTabindex": "off",
31+
"noStaticElementInteractions": "off"
32+
}
33+
}
34+
}
35+
}

deno-deploy-serve.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import {serveDir} from 'jsr:@std/http@1/file-server'
2+
3+
Deno.serve((req) => serveDir(req, {fsRoot: 'dist'}))

deno.jsonc

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,37 @@
44
"exports": "./src/utils.ts",
55
"nodeModulesDir": "auto",
66
"tasks": {
7-
"start": "deno run -A npm:vite --host",
8-
"preview": "deno run -A npm:vite preview",
9-
"check": "deno check src/**/*.ts src/**/*.tsx",
7+
"start": "vite --host --port 10000",
8+
"preview": "vite preview --port 10000",
9+
"check": "deno check --all src/**/*.ts src/**/*.tsx",
1010
"lint": "deno lint",
1111
"test": "deno test",
12-
"build": "deno run -A npm:vite build",
13-
"pre-commit": "deno task lint && deno task test && deno task build",
14-
"deploy": "deno run npm:@fleek-platform/cli sites deploy"
15-
},
16-
"publish": {
17-
"include": [
18-
"README.md",
19-
"deno.json",
20-
"package.json",
21-
"src/utils.ts"
22-
]
12+
"build": "vite build",
13+
"pre-commit": "deno task check && deno task lint && deno task test && deno task build",
14+
"deploy": {
15+
"command": "deno deploy dist",
16+
"dependencies": [ "build" ]
17+
}
2318
},
24-
"include": [ "src/**/*.ts", "src/**/*.tsx" ],
2519
"unstable": [ "sloppy-imports" ],
20+
// "exclude": [ ".history", /*"dist", "dev-dist"*/ ],
21+
"compilerOptions": {
22+
"jsx": "react-jsx",
23+
"jsxImportSource": "react",
24+
"lib": [ "ESNext", "DOM", "DOM.Iterable", "deno.ns" ],
25+
"types": [ "node", "vite/client" ]
26+
},
2627
"lint": {
27-
"include": ["src/"],
2828
"rules": {
2929
"tags": [ "recommended" ],
30-
"exclude": [
31-
"no-cond-assign",
32-
"no-sloppy-imports",
33-
"jsx-button-has-type"
34-
]
30+
"exclude": [ "no-cond-assign", "no-process-global", "no-sloppy-imports", "jsx-button-has-type" ]
3531
}
3632
},
37-
"compilerOptions": {
38-
"jsx": "react-jsx",
39-
"lib": [ "ESNext", "DOM", "DOM.Iterable" ],
40-
"types": [ "node", "vite/client" ]
33+
"publish": {
34+
"include": [ "README.md", "deno.json", "package.json", "src/utils.ts" ]
35+
},
36+
"deploy": {
37+
"org": "kuchta",
38+
"app": "radixverse"
4139
}
4240
}

0 commit comments

Comments
 (0)