step4
This commit is contained in:
parent
a8779ac0c8
commit
856e75415b
46
index.html
46
index.html
@ -4,51 +4,11 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="stylesheet" href="/src/styles.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Tauri App</title>
|
||||
<title>SheetJS x Tauri</title>
|
||||
<script type="module" src="/src/main.ts" defer></script>
|
||||
<style>
|
||||
.logo.vite:hover {
|
||||
filter: drop-shadow(0 0 2em #747bff);
|
||||
}
|
||||
|
||||
.logo.typescript:hover {
|
||||
filter: drop-shadow(0 0 2em #2d79c7);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Welcome to Tauri!</h1>
|
||||
|
||||
<div class="row">
|
||||
<a href="https://vitejs.dev" target="_blank">
|
||||
<img src="/src/assets/vite.svg" class="logo vite" alt="Vite logo" />
|
||||
</a>
|
||||
<a href="https://tauri.app" target="_blank">
|
||||
<img
|
||||
src="/src/assets/tauri.svg"
|
||||
class="logo tauri"
|
||||
alt="Tauri logo"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://www.typescriptlang.org/docs" target="_blank">
|
||||
<img
|
||||
src="/src/assets/typescript.svg"
|
||||
class="logo typescript"
|
||||
alt="typescript logo"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p>Click on the Tauri logo to learn more about the framework</p>
|
||||
|
||||
<form class="row" id="greet-form">
|
||||
<input id="greet-input" placeholder="Enter a name..." />
|
||||
<button type="submit">Greet</button>
|
||||
</form>
|
||||
|
||||
<p id="greet-msg"></p>
|
||||
</div>
|
||||
<div id="container" class="container"></div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
86
src/App.tsx
Normal file
86
src/App.tsx
Normal file
@ -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<any[][]>([[]])
|
||||
const [origin, setOrigin] = useState("");
|
||||
|
||||
const update = (wb: WorkBook) => {
|
||||
const ws = wb.Sheets[wb.SheetNames[0]];
|
||||
const d = utils.sheet_to_json<any[]>(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<Uint8Array>("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 ( <div>
|
||||
<h1><a href="https://sheetjs.com" target="_blank">
|
||||
<img src="https://sheetjs.com/sketch128.png" className="logo" alt="SheetJS" />
|
||||
SheetJS × Tauri {version}</a></h1>
|
||||
|
||||
<div className="centre"><button type="button" onclick={openFile}>Load Data</button> or
|
||||
<button type="button" onclick={saveFile}>Save Data</button></div>
|
||||
<p className="centre"><b className="centre">Data from { origin }</b></p>
|
||||
<table className="center"><tbody>
|
||||
{data.map((row) => <tr>
|
||||
{row.map((cell) => <td>{cell}</td>)}
|
||||
</tr>)}
|
||||
</tbody></table>
|
||||
</div>
|
||||
);
|
||||
}
|
25
src/main.ts
25
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!);
|
116
src/styles.css
116
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;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "preserve",
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
|
@ -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`
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user