UPDATE: split the webapp in a widget and the app itself
This splits the webapp in: * IronCalc (the widget to be published on npmjs) * The frontend for our "service" * Adds "dummy code" for the backend using sqlite
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
target/*
|
target/*
|
||||||
|
**/node_modules/**
|
||||||
.DS_Store
|
.DS_Store
|
||||||
8
Cargo.lock
generated
@@ -389,7 +389,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ironcalc"
|
name = "ironcalc"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitcode",
|
"bitcode",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -405,7 +405,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ironcalc_base"
|
name = "ironcalc_base"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitcode",
|
"bitcode",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -679,7 +679,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyroncalc"
|
name = "pyroncalc"
|
||||||
version = "0.1.2"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ironcalc",
|
"ironcalc",
|
||||||
"pyo3",
|
"pyo3",
|
||||||
@@ -953,7 +953,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm"
|
name = "wasm"
|
||||||
version = "0.1.3"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ironcalc_base",
|
"ironcalc_base",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ members = [
|
|||||||
|
|
||||||
exclude = [
|
exclude = [
|
||||||
"generate_locale",
|
"generate_locale",
|
||||||
|
"webapp/app.ironcalc.com/server",
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|||||||
5
Makefile
@@ -2,7 +2,8 @@
|
|||||||
lint:
|
lint:
|
||||||
cargo fmt -- --check
|
cargo fmt -- --check
|
||||||
cargo clippy --all-targets --all-features -- -W clippy::unwrap_used -W clippy::expect_used -W clippy::panic -D warnings
|
cargo clippy --all-targets --all-features -- -W clippy::unwrap_used -W clippy::expect_used -W clippy::panic -D warnings
|
||||||
cd webapp && npm install && npm run check
|
cd webapp/IronCalc/ && npm install && npm run check
|
||||||
|
cd webapp/app.ironcalc.com/frontend/ && npm install && npm run check
|
||||||
|
|
||||||
.PHONY: format
|
.PHONY: format
|
||||||
format:
|
format:
|
||||||
@@ -15,7 +16,7 @@ tests: lint
|
|||||||
# Regretabbly we need to build the wasm twice, once for the nodejs tests
|
# Regretabbly we need to build the wasm twice, once for the nodejs tests
|
||||||
# and a second one for the vitest.
|
# and a second one for the vitest.
|
||||||
cd bindings/wasm/ && wasm-pack build --target nodejs && node tests/test.mjs && make
|
cd bindings/wasm/ && wasm-pack build --target nodejs && node tests/test.mjs && make
|
||||||
cd webapp && npm run test
|
cd webapp/IronCalc/ && npm run test
|
||||||
cd bindings/python && ./run_tests.sh && ./run_examples.sh
|
cd bindings/python && ./run_tests.sh && ./run_examples.sh
|
||||||
|
|
||||||
.PHONY: remove-artifacts
|
.PHONY: remove-artifacts
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ironcalc_base"
|
name = "ironcalc_base"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
authors = ["Nicolás Hatcher <nicolas@theuniverse.today>"]
|
authors = ["Nicolás Hatcher <nicolas@theuniverse.today>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
homepage = "https://www.ironcalc.com"
|
homepage = "https://www.ironcalc.com"
|
||||||
repository = "https://github.com/ironcalc/ironcalc/"
|
repository = "https://github.com/ironcalc/ironcalc/"
|
||||||
description = "The democratization of spreadsheets"
|
description = "Open source spreadsheet engine"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pyroncalc"
|
name = "pyroncalc"
|
||||||
version = "0.1.2"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ crate-type = ["cdylib"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
xlsx = { package= "ironcalc", path = "../../xlsx", version = "0.2.0" }
|
xlsx = { package= "ironcalc", path = "../../xlsx", version = "0.3.0" }
|
||||||
pyo3 = { version = "0.22.3", features = ["extension-module"] }
|
pyo3 = { version = "0.22.3", features = ["extension-module"] }
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "ironcalc"
|
name = "ironcalc"
|
||||||
version = "0.1.2"
|
version = "0.3.0"
|
||||||
description = "Create, edit and evaluate Excel spreadsheets"
|
description = "Create, edit and evaluate Excel spreadsheets"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
keywords = [
|
keywords = [
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm"
|
name = "wasm"
|
||||||
version = "0.1.3"
|
version = "0.3.0"
|
||||||
authors = ["Nicolas Hatcher <nicolas@theuniverse.today>"]
|
authors = ["Nicolas Hatcher <nicolas@theuniverse.today>"]
|
||||||
description = "IronCalc Web bindings"
|
description = "IronCalc Web bindings"
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
@@ -14,7 +14,7 @@ crate-type = ["cdylib"]
|
|||||||
# Uses `../ironcalc/base` when used locally, and uses
|
# Uses `../ironcalc/base` when used locally, and uses
|
||||||
# the inicated version from crates.io when published.
|
# the inicated version from crates.io when published.
|
||||||
# https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#multiple-locations
|
# https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#multiple-locations
|
||||||
ironcalc_base = { path = "../../base", version = "0.2", features = ["use_regex_lite"] }
|
ironcalc_base = { path = "../../base", version = "0.3", features = ["use_regex_lite"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
wasm-bindgen = "0.2.92"
|
wasm-bindgen = "0.2.92"
|
||||||
serde-wasm-bindgen = "0.4"
|
serde-wasm-bindgen = "0.4"
|
||||||
|
|||||||
2
webapp/IronCalc/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules/*
|
||||||
|
dist/*
|
||||||
3127
webapp/package-lock.json → webapp/IronCalc/package-lock.json
generated
@@ -1,12 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "ironcalc",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.2.0",
|
"version": "0.3.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"main": "./dist/ironcalc.js",
|
||||||
|
"module": "./dist/ironcalc.js",
|
||||||
|
"source": "./src/index.ts",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "vite build && tsc",
|
||||||
"preview": "vite preview",
|
|
||||||
"check": "biome check ./src",
|
"check": "biome check ./src",
|
||||||
"check-write": "biome check --write ./src",
|
"check-write": "biome check --write ./src",
|
||||||
"test": "vitest run"
|
"test": "vitest run"
|
||||||
@@ -14,24 +17,30 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.11.4",
|
"@emotion/react": "^11.11.4",
|
||||||
"@emotion/styled": "^11.11.5",
|
"@emotion/styled": "^11.11.5",
|
||||||
"@ironcalc/wasm": "file:../bindings/wasm/pkg",
|
"@ironcalc/wasm": "file:../../bindings/wasm/pkg",
|
||||||
"@mui/material": "^5.15.15",
|
"@mui/material": "^5.15.15",
|
||||||
"i18next": "^23.11.1",
|
"i18next": "^23.11.1",
|
||||||
"lucide-react": "^0.427.0",
|
"lucide-react": "^0.427.0",
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-colorful": "^5.6.1",
|
"react-colorful": "^5.6.1",
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"react-i18next": "^13.5.0"
|
"react-i18next": "^13.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "1.8.3",
|
"@biomejs/biome": "1.8.3",
|
||||||
"@types/react": "^18.2.75",
|
|
||||||
"@types/react-dom": "^18.2.24",
|
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "~5.6.2",
|
||||||
"vite": "^5.2.8",
|
"vite": "^6.0.5",
|
||||||
"vite-plugin-svgr": "^4.2.0",
|
"vite-plugin-svgr": "^4.2.0",
|
||||||
"vitest": "^2.0.5"
|
"vitest": "^2.0.5",
|
||||||
|
"react": "^18.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^18.0.0",
|
||||||
|
"react": "^18.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
21
webapp/IronCalc/src/IronCalc.tsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import "./index.css";
|
||||||
|
import type { Model } from "@ironcalc/wasm";
|
||||||
|
import ThemeProvider from "@mui/material/styles/ThemeProvider";
|
||||||
|
import Workbook from "./components/workbook.tsx";
|
||||||
|
import { WorkbookState } from "./components/workbookState.ts";
|
||||||
|
import { theme } from "./theme.ts";
|
||||||
|
import "./i18n";
|
||||||
|
|
||||||
|
interface IronCalcProperties {
|
||||||
|
model: Model;
|
||||||
|
}
|
||||||
|
|
||||||
|
function IronCalc(properties: IronCalcProperties) {
|
||||||
|
return (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<Workbook model={properties.model} workbookState={new WorkbookState()} />
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IronCalc;
|
||||||
@@ -5,9 +5,7 @@ import type {
|
|||||||
WorksheetProperties,
|
WorksheetProperties,
|
||||||
} from "@ironcalc/wasm";
|
} from "@ironcalc/wasm";
|
||||||
import { styled } from "@mui/material/styles";
|
import { styled } from "@mui/material/styles";
|
||||||
import { PaintRoller } from "lucide-react";
|
|
||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import ReactDOMServer from "react-dom/server";
|
|
||||||
import SheetTabBar from "./SheetTabBar/SheetTabBar";
|
import SheetTabBar from "./SheetTabBar/SheetTabBar";
|
||||||
import {
|
import {
|
||||||
COLUMN_WIDTH_SCALE,
|
COLUMN_WIDTH_SCALE,
|
||||||
@@ -143,16 +141,10 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
|
|||||||
// FIXME: This is so that the cursor indicates there are styles to be pasted
|
// FIXME: This is so that the cursor indicates there are styles to be pasted
|
||||||
const el = rootRef.current?.getElementsByClassName("sheet-container")[0];
|
const el = rootRef.current?.getElementsByClassName("sheet-container")[0];
|
||||||
if (el) {
|
if (el) {
|
||||||
|
// Taken from lucide icons: <PaintRoller /> and rotated.
|
||||||
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-paint-roller" style="transform:rotate(-8deg)"><rect width="16" height="6" x="2" y="2" rx="2"></rect><path d="M10 16v-2a2 2 0 0 1 2-2h8a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2"></path><rect width="4" height="6" x="8" y="16" rx="1"></rect></svg>`;
|
||||||
(el as HTMLElement).style.cursor =
|
(el as HTMLElement).style.cursor =
|
||||||
`url('data:image/svg+xml;utf8,${encodeURIComponent(
|
`url('data:image/svg+xml;utf8,${encodeURIComponent(svg)}'), auto`;
|
||||||
ReactDOMServer.renderToString(
|
|
||||||
<PaintRoller
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
style={{ transform: "rotate(-8deg)" }}
|
|
||||||
/>,
|
|
||||||
),
|
|
||||||
)}'), auto`;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 869 B After Width: | Height: | Size: 869 B |
|
Before Width: | Height: | Size: 538 B After Width: | Height: | Size: 538 B |
|
Before Width: | Height: | Size: 498 B After Width: | Height: | Size: 498 B |
|
Before Width: | Height: | Size: 498 B After Width: | Height: | Size: 498 B |
|
Before Width: | Height: | Size: 586 B After Width: | Height: | Size: 586 B |
|
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 539 B |
|
Before Width: | Height: | Size: 513 B After Width: | Height: | Size: 513 B |
|
Before Width: | Height: | Size: 542 B After Width: | Height: | Size: 542 B |
|
Before Width: | Height: | Size: 538 B After Width: | Height: | Size: 538 B |
|
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 290 B |
|
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 539 B |
|
Before Width: | Height: | Size: 659 B After Width: | Height: | Size: 659 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1004 B After Width: | Height: | Size: 1004 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 929 B After Width: | Height: | Size: 929 B |
|
Before Width: | Height: | Size: 726 B After Width: | Height: | Size: 726 B |
|
Before Width: | Height: | Size: 725 B After Width: | Height: | Size: 725 B |
|
Before Width: | Height: | Size: 706 B After Width: | Height: | Size: 706 B |
|
Before Width: | Height: | Size: 706 B After Width: | Height: | Size: 706 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
5
webapp/IronCalc/src/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import init, { Model } from "@ironcalc/wasm";
|
||||||
|
import IronCalc from "./IronCalc";
|
||||||
|
import { IronCalcIcon, IronCalcLogo } from "./icons";
|
||||||
|
|
||||||
|
export { init, Model, IronCalc, IronCalcIcon, IronCalcLogo };
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import { createTheme } from "@mui/material/styles";
|
import { createTheme } from "@mui/material/styles";
|
||||||
import "./fonts.css";
|
|
||||||
|
|
||||||
export const theme = createTheme({
|
export const theme = createTheme({
|
||||||
typography: {
|
typography: {
|
||||||
@@ -5,13 +5,15 @@
|
|||||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
"declaration": true,
|
||||||
|
|
||||||
/* Bundler mode */
|
/* Bundler mode */
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "node",
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true,
|
"emitDeclarationOnly": true,
|
||||||
|
// "noEmit": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
/* Linting */
|
/* Linting */
|
||||||
@@ -19,7 +21,8 @@
|
|||||||
"noUnusedLocals": false,
|
"noUnusedLocals": false,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"esModuleInterop": true
|
"esModuleInterop": true,
|
||||||
|
"outDir": "dist",
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src"],
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
|
"declaration": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
37
webapp/IronCalc/vite.config.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import svgr from 'vite-plugin-svgr';
|
||||||
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
lib: {
|
||||||
|
entry: resolve(__dirname, 'src/index.ts'),
|
||||||
|
name: 'IronCalc',
|
||||||
|
// the proper extensions will be added
|
||||||
|
fileName: 'ironcalc',
|
||||||
|
},
|
||||||
|
rollupOptions: {
|
||||||
|
// make sure to externalize deps that shouldn't be bundled
|
||||||
|
// into your library
|
||||||
|
external: ['react', 'react-dom', '@ironcalc/wasm'],
|
||||||
|
output: {
|
||||||
|
// Provide global variables to use in the UMD build
|
||||||
|
// for externalized deps
|
||||||
|
globals: {
|
||||||
|
react: 'React',
|
||||||
|
'react-dom': 'ReactDOM',
|
||||||
|
'@ironcalc/wasm': 'IronCalc',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [react(), svgr()],
|
||||||
|
server: {
|
||||||
|
fs: {
|
||||||
|
// Allow serving files from one level up to the project root
|
||||||
|
allow: ['..'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
7
webapp/app.ironcalc.com/Caddyfile
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
:2080
|
||||||
|
|
||||||
|
# rocket API
|
||||||
|
reverse_proxy /api/* 127.0.0.1:8000
|
||||||
|
|
||||||
|
# everything else is the frontend
|
||||||
|
reverse_proxy :5173
|
||||||
44
webapp/app.ironcalc.com/README.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# IronCalc service application
|
||||||
|
|
||||||
|
This directory contains the code (frontend and backend) to run the code deployed at https://app.ironcalc.com
|
||||||
|
|
||||||
|
## Development build:
|
||||||
|
|
||||||
|
1. Run in this folder `caddy run` (that just just a proxy for the front end and backend).
|
||||||
|
You will need to leave it running all the time.
|
||||||
|
2. In the server folder run `cargo run`
|
||||||
|
3. In the frontend folder `npm install` and `npm run dev`
|
||||||
|
|
||||||
|
That's it if you point your browser to localhost:2080 you should see the app.
|
||||||
|
|
||||||
|
Note that step three involves alo building thw wasm bindings and the widget
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
The development environment is very close to a deployment environment.
|
||||||
|
|
||||||
|
### Build the server binary:
|
||||||
|
|
||||||
|
In the server directory run:
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo build --release
|
||||||
|
```
|
||||||
|
|
||||||
|
You will find a single binary in target/release/ironcalc_server
|
||||||
|
|
||||||
|
### Build the frontend files
|
||||||
|
|
||||||
|
In the frontend folder:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
That will create a bunch of files that you should copy to your server
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
Deployment details, brotli, logs, stats, Postgres, systemctl files, ...
|
||||||
|
|
||||||
24
webapp/app.ironcalc.com/frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# 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?
|
||||||
17
webapp/app.ironcalc.com/frontend/README.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# IronCalc application
|
||||||
|
|
||||||
|
This is the front end deployed at https:://app.ironcalc.com
|
||||||
|
|
||||||
|
|
||||||
|
To build for production:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
A development build:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
19
webapp/app.ironcalc.com/frontend/biome.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"organizeImports": { "enabled": true },
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"correctness": { "noUnusedImports": "error" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"indentStyle": "space",
|
||||||
|
"indentWidth": 2
|
||||||
|
},
|
||||||
|
"css": {
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -12,6 +12,5 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
<script defer data-domain="app.ironcalc.com" src="https://plausible.io/js/script.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
2834
webapp/app.ironcalc.com/frontend/package-lock.json
generated
Normal file
32
webapp/app.ironcalc.com/frontend/package.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "frontend",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.3.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc -b && vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"check": "biome check ./src",
|
||||||
|
"check-write": "biome check --write ./src"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.14.0",
|
||||||
|
"@emotion/styled": "^11.14.0",
|
||||||
|
"@ironcalc/ironcalc": "file:../../IronCalc",
|
||||||
|
"@mui/material": "^6.3.1",
|
||||||
|
"lucide": "^0.469.0",
|
||||||
|
"lucide-react": "^0.469.0",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@biomejs/biome": "1.8.3",
|
||||||
|
"@types/react": "^18.3.18",
|
||||||
|
"@types/react-dom": "^18.3.5",
|
||||||
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
|
"typescript": "~5.6.2",
|
||||||
|
"vite": "^6.0.5",
|
||||||
|
"vite-plugin-svgr": "^4.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
import "./App.css";
|
import "./App.css";
|
||||||
import Workbook from "./components/workbook";
|
|
||||||
import "./i18n";
|
|
||||||
import styled from "@emotion/styled";
|
import styled from "@emotion/styled";
|
||||||
import init, { Model } from "@ironcalc/wasm";
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { FileBar } from "./AppComponents/FileBar";
|
import { FileBar } from "./components/FileBar";
|
||||||
import {
|
import {
|
||||||
get_documentation_model,
|
get_documentation_model,
|
||||||
get_model,
|
get_model,
|
||||||
uploadFile,
|
uploadFile,
|
||||||
} from "./AppComponents/rpc";
|
} from "./components/rpc";
|
||||||
import {
|
import {
|
||||||
createNewModel,
|
createNewModel,
|
||||||
deleteSelectedModel,
|
deleteSelectedModel,
|
||||||
@@ -17,15 +14,13 @@ import {
|
|||||||
saveModelToStorage,
|
saveModelToStorage,
|
||||||
saveSelectedModelInStorage,
|
saveSelectedModelInStorage,
|
||||||
selectModelFromStorage,
|
selectModelFromStorage,
|
||||||
} from "./AppComponents/storage";
|
} from "./components/storage";
|
||||||
import { WorkbookState } from "./components/workbookState";
|
|
||||||
import { IronCalcIcon } from "./icons";
|
// From IronCalc
|
||||||
|
import { IronCalc, IronCalcIcon, Model, init } from "@ironcalc/ironcalc";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [model, setModel] = useState<Model | null>(null);
|
const [model, setModel] = useState<Model | null>(null);
|
||||||
const [workbookState, setWorkbookState] = useState<WorkbookState | null>(
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function start() {
|
async function start() {
|
||||||
@@ -60,12 +55,11 @@ function App() {
|
|||||||
const newModel = loadModelFromStorageOrCreate();
|
const newModel = loadModelFromStorageOrCreate();
|
||||||
setModel(newModel);
|
setModel(newModel);
|
||||||
}
|
}
|
||||||
setWorkbookState(new WorkbookState());
|
|
||||||
}
|
}
|
||||||
start();
|
start();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!model || !workbookState) {
|
if (!model) {
|
||||||
return (
|
return (
|
||||||
<Loading>
|
<Loading>
|
||||||
<IronCalcIcon style={{ width: 24, height: 24, marginBottom: 16 }} />
|
<IronCalcIcon style={{ width: 24, height: 24, marginBottom: 16 }} />
|
||||||
@@ -114,7 +108,7 @@ function App() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Workbook model={model} workbookState={workbookState} />
|
<IronCalc model={model} />
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import styled from "@emotion/styled";
|
import styled from "@emotion/styled";
|
||||||
import type { Model } from "@ironcalc/wasm";
|
import type { Model } from "@ironcalc/ironcalc";
|
||||||
|
import { IronCalcIcon, IronCalcLogo } from "@ironcalc/ironcalc";
|
||||||
import { CircleCheck } from "lucide-react";
|
import { CircleCheck } from "lucide-react";
|
||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
import { IronCalcIcon, IronCalcLogo } from "./../icons";
|
// import { IronCalcIcon, IronCalcLogo } from "./../icons";
|
||||||
import { FileMenu } from "./FileMenu";
|
import { FileMenu } from "./FileMenu";
|
||||||
import { ShareButton } from "./ShareButton";
|
import { ShareButton } from "./ShareButton";
|
||||||
import { WorkbookTitle } from "./WorkbookTitle";
|
import { WorkbookTitle } from "./WorkbookTitle";
|
||||||
@@ -14,7 +14,6 @@ function UploadFileDialog(properties: {
|
|||||||
const { onModelUpload } = properties;
|
const { onModelUpload } = properties;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const root = document.getElementById("root");
|
|
||||||
if (crossRef.current) {
|
if (crossRef.current) {
|
||||||
crossRef.current.focus();
|
crossRef.current.focus();
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Model } from "@ironcalc/wasm";
|
import { Model } from "@ironcalc/ironcalc";
|
||||||
import { base64ToBytes, bytesToBase64 } from "./util";
|
import { base64ToBytes, bytesToBase64 } from "./util";
|
||||||
|
|
||||||
const MAX_WORKBOOKS = 50;
|
const MAX_WORKBOOKS = 50;
|
||||||