diff --git a/base/src/lib.rs b/base/src/lib.rs index a5c632b..8db4ceb 100644 --- a/base/src/lib.rs +++ b/base/src/lib.rs @@ -58,3 +58,4 @@ pub mod mock_time; pub use model::get_milliseconds_since_epoch; pub use model::Model; pub use user_model::UserModel; +pub use user_model::BorderArea; diff --git a/base/src/new_empty.rs b/base/src/new_empty.rs index 3b01cc4..3167f92 100644 --- a/base/src/new_empty.rs +++ b/base/src/new_empty.rs @@ -353,7 +353,14 @@ impl Model { let now = dt.format("%Y-%m-%dT%H:%M:%SZ").to_string(); let mut views = HashMap::new(); - views.insert(0, WorkbookView { sheet: 0 }); + views.insert( + 0, + WorkbookView { + sheet: 0, + window_width: 800, + window_height: 600, + }, + ); // String versions of the locale are added here to simplify the serialize/deserialize logic let workbook = Workbook { diff --git a/base/src/types.rs b/base/src/types.rs index ebda7c2..b62cdb5 100644 --- a/base/src/types.rs +++ b/base/src/types.rs @@ -33,6 +33,10 @@ pub struct WorkbookSettings { pub struct WorkbookView { /// The index of the currently selected sheet. pub sheet: u32, + /// The current width of the window + pub window_width: i64, + /// The current heigh of the window + pub window_height: i64, } /// An internal representation of an IronCalc Workbook diff --git a/base/src/user_model.rs b/base/src/user_model/common.rs similarity index 84% rename from base/src/user_model.rs rename to base/src/user_model/common.rs index 9351f53..01ffbaf 100644 --- a/base/src/user_model.rs +++ b/base/src/user_model/common.rs @@ -2,7 +2,6 @@ use std::{collections::HashMap, fmt::Debug}; -use bitcode::{Decode, Encode}; use serde::{Deserialize, Serialize}; use crate::{ @@ -13,180 +12,35 @@ use crate::{ }, model::Model, types::{ - Alignment, BorderItem, BorderStyle, Cell, CellType, Col, HorizontalAlignment, Row, - SheetProperties, Style, VerticalAlignment, + Alignment, BorderItem, BorderStyle, CellType, Col, HorizontalAlignment, SheetProperties, + Style, VerticalAlignment, }, utils::is_valid_hex_color, }; +use crate::user_model::history::{ + ColumnData, Diff, DiffList, DiffType, History, QueueDiffs, RowData, +}; + #[derive(Serialize, Deserialize)] -#[cfg_attr(test, derive(PartialEq, Debug))] -pub struct SelectedView { - pub sheet: u32, - pub row: i32, - pub column: i32, - pub range: [i32; 4], - pub top_row: i32, - pub left_column: i32, +pub enum BorderType { + All, + Inner, + Outer, + Top, + Right, + Bottom, + Left, + CenterH, + CenterV, + None, } -#[derive(Clone, Encode, Decode)] -struct RowData { - row: Option, - data: HashMap, -} - -#[derive(Clone, Encode, Decode)] -struct ColumnData { - column: Option, - data: HashMap, -} - -#[derive(Clone, Encode, Decode)] -enum Diff { - // Cell diffs - SetCellValue { - sheet: u32, - row: i32, - column: i32, - new_value: String, - old_value: Box>, - }, - CellClearContents { - sheet: u32, - row: i32, - column: i32, - old_value: Box>, - }, - CellClearAll { - sheet: u32, - row: i32, - column: i32, - old_value: Box>, - old_style: Box + + + + + + diff --git a/webapp/src/icons/border-top.svg b/webapp/src/icons/border-top.svg new file mode 100644 index 0000000..9051f73 --- /dev/null +++ b/webapp/src/icons/border-top.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/webapp/src/icons/decrease-decimal.svg b/webapp/src/icons/decrease-decimal.svg new file mode 100644 index 0000000..ab46d1e --- /dev/null +++ b/webapp/src/icons/decrease-decimal.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/webapp/src/icons/delete-column.svg b/webapp/src/icons/delete-column.svg new file mode 100644 index 0000000..36fc423 --- /dev/null +++ b/webapp/src/icons/delete-column.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/webapp/src/icons/delete-row.svg b/webapp/src/icons/delete-row.svg new file mode 100644 index 0000000..ffebabf --- /dev/null +++ b/webapp/src/icons/delete-row.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/webapp/src/icons/fx.svg b/webapp/src/icons/fx.svg new file mode 100644 index 0000000..fb9e203 --- /dev/null +++ b/webapp/src/icons/fx.svg @@ -0,0 +1,3 @@ + + + diff --git a/webapp/src/icons/increase-decimal.svg b/webapp/src/icons/increase-decimal.svg new file mode 100644 index 0000000..c8ffa01 --- /dev/null +++ b/webapp/src/icons/increase-decimal.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/webapp/src/icons/index.ts b/webapp/src/icons/index.ts new file mode 100644 index 0000000..cad60ef --- /dev/null +++ b/webapp/src/icons/index.ts @@ -0,0 +1,46 @@ +import DecimalPlacesDecreaseIcon from "./decrease-decimal.svg?react"; +import DecimalPlacesIncreaseIcon from "./increase-decimal.svg?react"; + +import BorderBottomIcon from "./border-bottom.svg?react"; +import BorderCenterHIcon from "./border-center-h.svg?react"; +import BorderCenterVIcon from "./border-center-v.svg?react"; +import BorderInnerIcon from "./border-inner.svg?react"; +import BorderLeftIcon from "./border-left.svg?react"; +import BorderOuterIcon from "./border-outer.svg?react"; +import BorderRightIcon from "./border-right.svg?react"; +import BorderTopIcon from "./border-top.svg?react"; +import BorderNoneIcon from "./border-none.svg?react"; +import BorderStyleIcon from "./border-style.svg?react"; + +import DeleteColumnIcon from "./delete-column.svg?react"; +import DeleteRowIcon from "./delete-row.svg?react"; +import InsertColumnLeftIcon from "./insert-column-left.svg?react"; +import InsertColumnRightIcon from "./insert-column-right.svg?react"; +import InsertRowAboveIcon from "./insert-row-above.svg?react"; +import InsertRowBelow from "./insert-row-below.svg?react"; +import ArrowMiddleFromLine from "./arrow-middle-from-line.svg?react"; + +import Fx from "./fx.svg?react"; + +export { + ArrowMiddleFromLine, + DecimalPlacesDecreaseIcon, + DecimalPlacesIncreaseIcon, + BorderBottomIcon, + BorderCenterHIcon, + BorderCenterVIcon, + BorderInnerIcon, + BorderLeftIcon, + BorderOuterIcon, + BorderRightIcon, + BorderTopIcon, + BorderNoneIcon, + BorderStyleIcon, + DeleteColumnIcon, + DeleteRowIcon, + InsertColumnLeftIcon, + InsertColumnRightIcon, + InsertRowAboveIcon, + InsertRowBelow, + Fx, +}; diff --git a/webapp/src/icons/insert-column-left.svg b/webapp/src/icons/insert-column-left.svg new file mode 100644 index 0000000..1d6e56d --- /dev/null +++ b/webapp/src/icons/insert-column-left.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/webapp/src/icons/insert-column-right.svg b/webapp/src/icons/insert-column-right.svg new file mode 100644 index 0000000..5cc5178 --- /dev/null +++ b/webapp/src/icons/insert-column-right.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/webapp/src/icons/insert-row-above.svg b/webapp/src/icons/insert-row-above.svg new file mode 100644 index 0000000..336d193 --- /dev/null +++ b/webapp/src/icons/insert-row-above.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/webapp/src/icons/insert-row-below.svg b/webapp/src/icons/insert-row-below.svg new file mode 100644 index 0000000..8b7f88b --- /dev/null +++ b/webapp/src/icons/insert-row-below.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/webapp/src/index.css b/webapp/src/index.css new file mode 100644 index 0000000..ea1e941 --- /dev/null +++ b/webapp/src/index.css @@ -0,0 +1,4 @@ +body { + margin: 0; + padding: 0; +} diff --git a/webapp/src/locale/en_us.json b/webapp/src/locale/en_us.json new file mode 100644 index 0000000..d5838ea --- /dev/null +++ b/webapp/src/locale/en_us.json @@ -0,0 +1,50 @@ +{ + "toolbar": { + "redo": "Redo", + "undo": "Undo", + "copy_styles": "Copy styles", + "euro": "Format as Euro", + "percentage": "Format as Percentage", + "bold": "Bold", + "italic": "Italic", + "underline": "Underline", + "strike_through": "Strikethrough", + "align_left": "Align left", + "align_right": "Align right", + "align_center": "Align center", + "format_number": "Format number", + "font_color": "Font color", + "fill_color": "Fill color", + "borders": "Borders", + "decimal_places_increase": "Increase decimal places", + "decimal_places_decrease": "Decrease decimal places", + "format_menu": { + "auto": "Auto", + "number": "Number", + "percentage": "Percentage", + "currency_eur": "Euro (EUR)", + "currency_usd": "Dollar (USD", + "currency_gbp": "British Pound (GBD)", + "date_short": "Short date", + "date_long": "Long date", + "custom": "Custom", + "number_example": "1,000.00", + "percentage_example": "10%", + "currency_eur_example": "€", + "currency_usd_example": "$", + "currency_gbp_example": "£", + "date_short_example": "09/24/2024", + "date_long_example": "Tuesday, September 24, 2024" + } + }, + "num_fmt" :{ + "title": "Custom number format", + "label": "Number format", + "save": "Save" + }, + "sheet_rename": { + "rename": "Save", + "label": "New name", + "title": "Rename Sheet" + } +} \ No newline at end of file diff --git a/webapp/src/main.tsx b/webapp/src/main.tsx new file mode 100644 index 0000000..8239cba --- /dev/null +++ b/webapp/src/main.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App.tsx'; +import './index.css'; +import { theme } from './theme.ts'; +import ThemeProvider from '@mui/material/styles/ThemeProvider'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + + + , +); diff --git a/webapp/src/theme.ts b/webapp/src/theme.ts new file mode 100644 index 0000000..179ca43 --- /dev/null +++ b/webapp/src/theme.ts @@ -0,0 +1,66 @@ +import { createTheme } from "@mui/material/styles"; +import './fonts.css'; + +export const theme = createTheme({ + typography: { + fontFamily: "Inter", + }, + palette: { + common: { + black: "#272525", + white: "#FFF", + }, + primary: { + main: "#F2994A", + light: "#EFAA6D", + dark: "#D68742", + contrastText: "#FFF", + }, + secondary: { + main: "#2F80ED", + light: "#4E92EC", + dark: "#2B6EC8", + contrastText: "#FFF", + }, + error: { + main: "#EB5757", + light: "#E77A7A", + dark: "#CB4C4C", + contrastText: "#FFF", + }, + warning: { + main: "#F2C94C", + light: "#EED384", + dark: "#D6B244", + contrastText: "#FFF", + }, + info: { + main: "#9E9E9E", + light: "#E0E0E0", + dark: "#757575", + contrastText: "#FFF", + }, + success: { + main: "#27AE60", + light: "#57BD82", + dark: "#239152", + contrastText: "#FFF", + }, + grey: { + "50": "#F2F2F2", + "100": "#F5F5F5", + "200": "#EEEEEE", + "300": "#E0E0E0", + "400": "#BDBDBD", + "500": "#9E9E9E", + "600": "#757575", + "700": "#616161", + "800": "#424242", + "900": "#333333", + A100: "#F2F2F2", + A200: "#EEEEEE", + A400: "#bdbdbd", + A700: "#616161", + }, + }, +}); diff --git a/webapp/src/vite-env.d.ts b/webapp/src/vite-env.d.ts new file mode 100644 index 0000000..b1f45c7 --- /dev/null +++ b/webapp/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/webapp/tsconfig.json b/webapp/tsconfig.json new file mode 100644 index 0000000..47787c0 --- /dev/null +++ b/webapp/tsconfig.json @@ -0,0 +1,26 @@ +{ + "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": false, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "esModuleInterop": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/webapp/tsconfig.node.json b/webapp/tsconfig.node.json new file mode 100644 index 0000000..42872c5 --- /dev/null +++ b/webapp/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/webapp/vite.config.ts b/webapp/vite.config.ts new file mode 100644 index 0000000..60a7425 --- /dev/null +++ b/webapp/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import svgr from 'vite-plugin-svgr'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), svgr()], + server: { + fs: { + // Allow serving files from one level up to the project root + allow: ['..'], + }, + }, +}); diff --git a/xlsx/src/import/mod.rs b/xlsx/src/import/mod.rs index d130237..70426d9 100644 --- a/xlsx/src/import/mod.rs +++ b/xlsx/src/import/mod.rs @@ -93,6 +93,8 @@ fn load_xlsx_from_reader( 0, WorkbookView { sheet: selected_sheet, + window_width: 800, + window_height: 600, }, ); Ok(Workbook {