added file dropping support through `withDrop` hoc

addresses #2
pull/2/head
Michael Ochmann 3 years ago
parent 5022bdf318
commit ca9754cd10
  1. 3
      contextAPI.js
  2. 31
      src/Ation.js
  3. 1
      src/WindowManager.js
  4. 35
      src/ui/src/components/Ation.js
  5. 42
      src/ui/src/higherOrderComponents/withDrop.js
  6. 7
      src/ui/src/index.js

@ -4,5 +4,6 @@ const {contextBridge, ipcRenderer} = require("electron");
contextBridge.exposeInMainWorld("api", { contextBridge.exposeInMainWorld("api", {
openFileDialog : () => ipcRenderer.send("WindowManager::openFileDialog"), openFileDialog : () => ipcRenderer.send("WindowManager::openFileDialog"),
openFile : callback => ipcRenderer.on("Ation::openFile", (_, presentation) => callback(presentation)) onFileOpen : callback => ipcRenderer.on("Ation::openFile", (_, presentation) => callback(presentation)),
openFile : filePath => ipcRenderer.send("WindowManager::openFile", filePath)
}); });

@ -36,25 +36,28 @@ class Ation {
}); });
} }
async openFile() { async openFile(filePath = null) {
if (!this.windowManager.mainWindow) if (!this.windowManager.mainWindow)
return null; return null;
const result = await dialog.showOpenDialog(this.windowManager.mainWindow, { if (!filePath) {
title : "open file", const result = await dialog.showOpenDialog(this.windowManager.mainWindow, {
filters : [ title : "open file",
{ filters : [
name : "Markdown files", {
extensions : [".md"] name : "Markdown files",
} extensions : [".md"]
] }
}); ]
});
if (result.canceled || result.filePaths.length < 1) if (result.canceled || result.filePaths.length < 1)
return null; return;
filePath = result.filePaths[0];
}
const fileContents = await fs.readFile(result.filePaths[0], {encoding : "utf-8"}); const fileContents = await fs.readFile(filePath, {encoding : "utf-8"});
const basePath = path.dirname(result.filePaths[0]); const basePath = path.dirname(filePath);
const data = parser(fileContents); const data = parser(fileContents);

@ -18,6 +18,7 @@ class WindowManager {
app.whenReady().then(() => this.init()); app.whenReady().then(() => this.init());
ipcMain.on("WindowManager::openFileDialog", () => this.app.openFile()); ipcMain.on("WindowManager::openFileDialog", () => this.app.openFile());
ipcMain.on("WindowManager::openFile", (_, path) => this.app.openFile(path));
} }
init() { init() {

@ -19,7 +19,7 @@ const Ation = () => {
const [showTips, setShowTips] = useState(false); const [showTips, setShowTips] = useState(false);
useEffect(() => { useEffect(() => {
window.api.openFile(presentation => { window.api.onFileOpen(presentation => {
const [basePath, slideDeck] = presentation; const [basePath, slideDeck] = presentation;
if (!slideDeck) if (!slideDeck)
return; return;
@ -32,22 +32,25 @@ const Ation = () => {
window.api.openFileDialog(); window.api.openFileDialog();
} }
if (deck.length < 1)
return <NoFile openFile={openFile} />;
return ( return (
<SlideContext.Provider value={{slide, setSlide, mode, setMode, basePath}}> <>
<section className={`window${mode === Mode.PRESENT ? " fullscreen" : ""}`}> {deck.length < 1 ?
<Toolbar openFile={openFile} setShowTips={setShowTips} /> <NoFile openFile={openFile} />
<SlidesList deck={deck} /> : (
<main className="main"> <SlideContext.Provider value={{slide, setSlide, mode, setMode, basePath}}>
<Slide data={deck[slide] || null} /> <section className={`window${mode === Mode.PRESENT ? " fullscreen" : ""}`}>
</main> <Toolbar openFile={openFile} setShowTips={setShowTips} />
<Tips show={showTips} /> <SlidesList deck={deck} />
</section> <main className="main">
<Blackout show={mode === Mode.BLACKOUT} /> <Slide data={deck[slide] || null} />
<KeyboardControl mode={mode} setMode={setMode} deck={deck} openFile={openFile} setShowTips={setShowTips} /> </main>
</SlideContext.Provider> <Tips show={showTips} />
</section>
<Blackout show={mode === Mode.BLACKOUT} />
<KeyboardControl mode={mode} setMode={setMode} deck={deck} openFile={openFile} setShowTips={setShowTips} />
</SlideContext.Provider>
)}
</>
); );
}; };

@ -0,0 +1,42 @@
import React, {useState} from "react";
const extension = filename => {
const parts = filename.split('.');
return parts[parts.length - 1];
};
const withDrop = Component => () => {
const [drag, setDrag] = useState(false);
const handleDragOver = event => {
event.preventDefault();
event.stopPropagation();
setDrag(true);
};
const handleDragLeave = event => {
event.preventDefault();
event.stopPropagation();
setDrag(false);
}
const handleDrop = event => {
event.preventDefault();
event.stopPropagation();
const file = event.dataTransfer?.items[0].getAsFile();
if (extension(file.name.toLowerCase()) === "md") {
window.api.openFile(file.path);
}
setDrag(false);
};
return (
<section onDragLeave={handleDragLeave} onDragOver={handleDragOver} onDrop={handleDrop} style={{opacity : drag ? 0.2 : 1}}>
<Component />
</section>
);
};
export default withDrop;

@ -1,13 +1,16 @@
import React from "react"; import React from "react";
import ReactDOM from "react-dom/client"; import ReactDOM from "react-dom/client";
import Ation from "./components/Ation"; import Ation from "./components/Ation";
import withDrop from "./higherOrderComponents/withDrop";
import "./assets/css/ation.scss"; import "./assets/css/ation.scss";
const App = withDrop(Ation);
const root = ReactDOM.createRoot(document.getElementById("root")); const root = ReactDOM.createRoot(document.getElementById("root"));
root.render( root.render(
<React.StrictMode> <React.StrictMode>
<Ation /> <App />
</React.StrictMode> </React.StrictMode>
); );
Loading…
Cancel
Save