From 856e75415bcfc7257cc2794bbb62f1cdf79e2a06 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Mon, 25 Mar 2024 03:23:13 -0400 Subject: [PATCH] step4 --- index.html | 46 ++------------------ src/App.tsx | 86 ++++++++++++++++++++++++++++++++++++ src/main.ts | 25 ++--------- src/styles.css | 116 +++++-------------------------------------------- tsconfig.json | 1 + vite.config.ts | 11 +++++ 6 files changed, 115 insertions(+), 170 deletions(-) create mode 100644 src/App.tsx diff --git a/index.html b/index.html index 4175816..334857f 100644 --- a/index.html +++ b/index.html @@ -4,51 +4,11 @@ - Tauri App + SheetJS x Tauri - -
-

Welcome to Tauri!

- - - -

Click on the Tauri logo to learn more about the framework

- -
- - -
- -

-
+
- + \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..b462ce3 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,86 @@ +import { useEffect, useState } from 'kaioken' +import { read, write, utils, version, WorkBook } from 'xlsx'; +import { DialogFilter, message, open, save } from '@tauri-apps/api/dialog'; +import { fetch, ResponseType } from '@tauri-apps/api/http'; +import { readBinaryFile, writeBinaryFile } from '@tauri-apps/api/fs'; + +const filters: DialogFilter[] = [ + {name: "Excel Binary Workbook", extensions: ["xlsb"]}, + {name: "Excel Workbook", extensions: ["xlsx"]}, + {name: "Excel 97-2004 Workbook", extensions: ["xls"]}, + {name: "Excel 2003 XML Spreadsheet", extensions: ["xml"]}, + {name: "Symbolic Link", extensions: ["slk"]}, + {name: "Flat OpenDocument Spreadsheet", extensions: ["fods"]}, + {name: "OpenDocument Spreadsheet", extensions: ["fods"]}, + // ... +]; + +export default function SheetJSTauriKaioken() { + const [data, setData] = useState([[]]) + const [origin, setOrigin] = useState(""); + + const update = (wb: WorkBook) => { + const ws = wb.Sheets[wb.SheetNames[0]]; + const d = utils.sheet_to_json(ws, { header: 1}) + setData(d); + }; + + /* Load from File */ + const openFile = async() => { + try { + const selected = await open({ + title: "Open Spreadsheet", + multiple: false, + directory: false, + filters + }) as string; + const d = await readBinaryFile(selected); + const wb = read(d); + update(wb); + setOrigin(selected); + } catch(e) { await message((e as Error).message || (e as string), { title: "Load Error", type: "error"}); } + }; + + /* Save to File */ + const saveFile = async() => { + try { + const selected = await save({ + title: "Save to Spreadsheet", + filters + }); + if(!selected) throw new Error("No file selected"); + const ws = utils.aoa_to_sheet(data); + const wb = utils.book_new(); + utils.book_append_sheet(wb, ws, "SheetJSTauri"); + const d = write(wb, {type: "buffer", bookType: selected.slice(selected.lastIndexOf(".") + 1) as any}) as Uint8Array; + await writeBinaryFile(selected, d); + await message(`File saved to ${selected}`); + } catch(e) { await message((e as Error).message || (e as string), { title: "Save Error", type: "error"}); } + }; + + /* Download from https://sheetjs.com/pres.numbers */ + useEffect(() => {(async() => { + try { + setOrigin("https://sheetjs.com/pres.numbers"); + const response = await fetch("https://sheetjs.com/pres.numbers", { method: "GET", responseType: ResponseType.Binary }); + const wb = read(new Uint8Array(response.data)); + update(wb); + } catch(e) { await message((e as Error).message || (e as string), { title: "Fetch Error", type: "error"}); } + })(); }, []); + + return (
+

+ SheetJS + SheetJS × Tauri {version}

+ +
or +
+

Data from { origin }

+ + {data.map((row) => + {row.map((cell) => )} + )} +
{cell}
+
+ ); +} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 9f75eb8..daa3454 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,22 +1,5 @@ -import { invoke } from "@tauri-apps/api/tauri"; +import { mount } from "kaioken"; +import App from "./App"; -let greetInputEl: HTMLInputElement | null; -let greetMsgEl: HTMLElement | null; - -async function greet() { - if (greetMsgEl && greetInputEl) { - // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command - greetMsgEl.textContent = await invoke("greet", { - name: greetInputEl.value, - }); - } -} - -window.addEventListener("DOMContentLoaded", () => { - greetInputEl = document.querySelector("#greet-input"); - greetMsgEl = document.querySelector("#greet-msg"); - document.querySelector("#greet-form")?.addEventListener("submit", (e) => { - e.preventDefault(); - greet(); - }); -}); +const root = document.getElementById("container"); +mount(App, root!); \ No newline at end of file diff --git a/src/styles.css b/src/styles.css index f7de85b..69ba884 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,109 +1,13 @@ -:root { - font-family: Inter, Avenir, Helvetica, Arial, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 400; - - color: #0f0f0f; - background-color: #f6f6f6; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; -} - -.container { - margin: 0; - padding-top: 10vh; - display: flex; - flex-direction: column; - justify-content: center; - text-align: center; -} - .logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: 0.75s; + padding: 0px; + height: 64px; width: 64px; + vertical-align: middle; } - -.logo.tauri:hover { - filter: drop-shadow(0 0 2em #24c8db); -} - -.row { - display: flex; - justify-content: center; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} - -a:hover { - color: #535bf2; -} - -h1 { - text-align: center; -} - -input, -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - color: #0f0f0f; - background-color: #ffffff; - transition: border-color 0.25s; - box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); -} - -button { - cursor: pointer; -} - -button:hover { - border-color: #396cd8; -} -button:active { - border-color: #396cd8; - background-color: #e8e8e8; -} - -input, -button { - outline: none; -} - -#greet-input { - margin-right: 5px; -} - -@media (prefers-color-scheme: dark) { - :root { - color: #f6f6f6; - background-color: #2f2f2f; - } - - a:hover { - color: #24c8db; - } - - input, - button { - color: #ffffff; - background-color: #0f0f0f98; - } - button:active { - background-color: #0f0f0f69; - } +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); } +.centre { text-align: center; } +table.center { + margin-left: auto; + margin-right: auto; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 75abdef..2c75e81 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "jsx": "preserve", "target": "ES2020", "useDefineForClassFields": true, "module": "ESNext", diff --git a/vite.config.ts b/vite.config.ts index e2d6c4c..e7dfcf7 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,18 @@ import { defineConfig } from "vite"; +import kaioken from "vite-plugin-kaioken" // https://vitejs.dev/config/ export default defineConfig(async () => ({ + esbuild: { + jsxInject: `import * as kaioken from "kaioken"`, + jsx: "transform", + jsxFactory: "kaioken.createElement", + jsxFragment: "kaioken.fragment", + loader: "tsx", + include: ["**/*.tsx", "**/*.ts", "**/*.jsx", "**/*.js"], + }, + plugins: [kaioken()], + // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` //