more polishing for `v0.1.0`

pull/2/head v0.1.0
Michael Ochmann 3 years ago
parent ed35abf4d2
commit 48eec34628
  1. 2
      package.json
  2. 10
      src/Ation.js
  3. 3
      src/WindowManager.js
  4. 1
      src/ui/src/assets/css/_blackout.scss
  5. 20
      src/ui/src/assets/css/_forms.scss
  6. 74
      src/ui/src/assets/css/_slide.scss
  7. 4
      src/ui/src/assets/css/_slidesList.scss
  8. 3
      src/ui/src/assets/css/_variables.scss
  9. 14
      src/ui/src/components/Ation.js
  10. 15
      src/ui/src/components/KeyboardControl.js
  11. 3
      src/ui/src/components/NoFile.js
  12. 4
      src/ui/src/components/Slide.js
  13. 25
      src/ui/src/components/SlideItem.js
  14. 4
      src/ui/src/components/SlidesList.js
  15. 1
      src/ui/src/shared/SlideContext.js

@ -1,6 +1,6 @@
{
"name": "ation",
"version": "0.0.1",
"version": "0.1.0",
"description": "a simple presentation software",
"main": "main.js",
"scripts": {

@ -1,4 +1,6 @@
"use strict";
const {app, protocol} = require("electron");
const url = require("url");
const WindowManager = require("./WindowManager");
@ -9,6 +11,14 @@ class Ation {
if (Ation.Instances > 0)
throw new Error("Only one Instance of Ation possible");
this.windowManager = new WindowManager();
app.whenReady().then(async () => {
protocol.registerFileProtocol("slideimg", (request, callback) => {
const path = request.url.replace(/^slideimg:\/\//, "");
console.log(path);
callback(path);
});
});
}
}
Ation.Instances = 0;

@ -36,9 +36,10 @@ class WindowManager {
return null;
const fileContents = await fs.readFile(result.filePaths[0], {encoding : "utf-8"});
const basePath = path.dirname(result.filePaths[0]);
const data = parser(fileContents);
return data;
return [basePath, data];
});
}

@ -3,6 +3,7 @@
top: 0;
left: 0;
width: 100vw;
cursor: none;
height: 100vh;
z-index: 1000;
background: black;

@ -22,3 +22,23 @@ button {
vertical-align: middle;
}
}
.checkbox {
display: inline-block;
width: 2vw;
height: 2vw;
border: solid 1px color(hightlight);
color: color(hightlight);
position: relative;
&.checked {
&::before {
content: "X";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 1.8vw;
}
}
}

@ -1,33 +1,93 @@
.slide {
font-family: "Iosevka", sans-serif;
font-size: 2rem;
font-size: 4vw;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
user-select: none;
padding: 8vw;
text-align: center;
aspect-ratio: 1.333;
background: color(background);
color: color(foreground);
ul, ol, pre {
text-align: left;
}
ul, ol {
li.task {
list-style: none;
margin-left: -0.8em;
}
}
blockquote {
opacity: 0.5;
font-style: italic;
position: relative;
&::before, &::after {
position: absolute;
font-size: 8vw;
opacity: 0.1;
}
&::before {
top: 0;
left: 0;
margin-left: -4vw;
content: "";
}
&::after {
bottom: 0;
right: 0;
margin-right: -4vw;
content: "";
}
}
figure {
img {
max-width: 95%;
height: auto;
}
figcaption {
font-size: 1.8vw;
opacity: 0.6;
font-style: italic;
font-weight: normal;
}
}
&.title {
p {
font-style: italic;
font-size: 1.8rem;
font-size: 3.5vw;
color: color(scrollbar);
&:nth-of-type(2) {
font-size: 1.2rem;
font-size: 2.8vw;
}
}
}
h1 {
font-size: 4rem;
code:not([class*=language-]) {
font-weight: normal;
font-size: 0.9em;
color: color(hightlight);
}
code {
font-size: 1.2rem;
pre {
font-size: 1.5vw;
width: 90%;
padding: 4vw !important;
* {
font-weight: normal !important;
}
}
}

@ -16,5 +16,9 @@
margin: 5% 0 0 5%;
aspect-ratio: 1.333;
-webkit-transform-origin: top left;
&.active {
border: solid 3px color(hightlight);
}
}
}

@ -4,7 +4,8 @@ $colors : (
foreground : #ddd,
sidebarBackground : #333,
mainBackground : #222,
scrollbar : rgba(255,255,255,0.2)
scrollbar : rgba(255,255,255,0.2),
hightlight : lawngreen
);
:root {

@ -11,15 +11,17 @@ import Toolbar from "./Toolbar";
import SlideContext from "../shared/SlideContext";
const Ation = () => {
const [mode, setMode] = useState(Mode.NORMAL);
const [deck, setDeck] = useState([]);
const [slide, setSlide] = useState(0);
const [mode, setMode] = useState(Mode.NORMAL);
const [deck, setDeck] = useState([]);
const [slide, setSlide] = useState(0);
const [basePath, setBasePath] = useState("");
const openFile = async () => {
const slideDeck = await window.api.openFile();
const [basePath, slideDeck] = await window.api.openFile();
if (!slideDeck)
return;
setBasePath(basePath);
setDeck(slideDeck);
}
@ -27,7 +29,7 @@ const Ation = () => {
return <NoFile openFile={openFile} />;
return (
<SlideContext.Provider value={{slide, setSlide, mode, setMode}}>
<SlideContext.Provider value={{slide, setSlide, mode, setMode, basePath}}>
<section className={`window${mode === Mode.PRESENT ? " fullscreen" : ""}`}>
<Toolbar openFile={openFile} />
<SlidesList deck={deck} />
@ -36,7 +38,7 @@ const Ation = () => {
</main>
</section>
<Blackout show={mode === Mode.BLACKOUT} />
<KeyboardControl mode={mode} setMode={setMode} deck={deck} />
<KeyboardControl mode={mode} setMode={setMode} deck={deck} openFile={openFile} />
</SlideContext.Provider>
);
};

@ -3,12 +3,23 @@ import {useContext, useEffect} from "react";
import SlideContext from "../shared/SlideContext";
import Mode from "../models/Mode";
const KeyboardControl = ({mode, setMode, deck}) => {
const KeyboardControl = ({openFile, mode, setMode, deck}) => {
const {slide, setSlide} = useContext(SlideContext);
useEffect(() => {
const keyHandler = event => {
console.log(event.key);
switch(event.key) {
case "o":
if (!event.metaKey && !event.ctrlKey)
return;
openFile();
break;
default:
console.log(event.key);
}
if (!mode || !setMode || !deck)
return;
switch (event.key) {
case "F5":
if (deck.length <= 0)

@ -2,6 +2,8 @@ import React from "react";
import {Easel, Folder2Open} from "react-bootstrap-icons";
import KeyboardControl from "./KeyboardControl";
const NoFile = ({openFile}) => {
return (
<section className="no-file">
@ -14,6 +16,7 @@ const NoFile = ({openFile}) => {
<button onClick={openFile}><Folder2Open /> open</button>
</p>
</section>
<KeyboardControl openFile={openFile} />
</section>
);
};

@ -2,9 +2,9 @@ import React from "react";
import SlideItem from "./SlideItem";
const Slide = ({data, ...props}) => {
const Slide = ({data, className, ...props}) => {
return (
<article className={`slide${data?.title ? " title" : ""}`} {...props}>
<article className={`slide${data?.title ? " title" : ""} ${className}`} {...props}>
{data?.content.map((item, index) =>
<SlideItem item={item} key={index} />
)}

@ -1,8 +1,10 @@
import React, {useMemo} from "react";
import React, {useMemo, useContext} from "react";
import SyntaxHighlighter from "react-syntax-highlighter"
import {monokai} from "react-syntax-highlighter/dist/esm/styles/hljs";
import SlideContext from "../shared/SlideContext";
const Children = ({items}) => {
if (items instanceof Array)
return <>{items.map((child, index) => <SlideItem item={child} key={index} />)}</>;
@ -10,6 +12,8 @@ const Children = ({items}) => {
};
const SlideItem = ({item}) => {
const {basePath} = useContext(SlideContext);
const content = useMemo(() => {
console.log("ITEM",item);
switch (item.type) {
@ -21,12 +25,25 @@ const SlideItem = ({item}) => {
else
return <ul><Children items={item.items} /></ul>
case "list_item":
const prefix = item.task ? <input type="checkbox" defaultChecked={item.checked} /> : null;
return <li>{prefix} <Children items={item.tokens} /></li>
const prefix = item.task ? <span className={`checkbox${item.checked ? " checked" : ""}`}></span> : null;
return <li className={item.task ? "task" : ""}>{prefix} <Children items={item.tokens} /></li>
case "image":
return (
<figure>
<img src={`slideimg://${basePath}/${item.href.replace(/\.\//, "")}`} alt={item.text} />
{item.text?.length > 0 ?
<figcaption>{item.text}</figcaption>
: null}
</figure>
)
case "blockquote":
return <blockquote><Children items={item.tokens} /></blockquote>
case "paragraph":
return <p><Children items={item.tokens} /></p>
case "code":
return <SyntaxHighlighter style={monokai} language={item.lang}>{item.text}</SyntaxHighlighter>
case "codespan":
return <code>{item.text}</code>
case "strong":
return <b><Children items={item.tokens} /></b>
case "em":
@ -36,7 +53,7 @@ const SlideItem = ({item}) => {
default:
return JSON.stringify(item);
}
}, [item]);
}, [item, basePath]);
return (
<>

@ -36,9 +36,9 @@ const SlidesList = ({deck}) => {
return (
<aside className="slides-list" ref={container}>
{deck.map((slide, index) => (
{deck.map((currentSlide, index) => (
<div className="slide-wrap" key={index}>
<Slide data={slide} style={{transform : `scale(${scale}) translateX(0)`}} onClick={() => setSlide(index)} />
<Slide data={currentSlide} className={index === slide ? "active" : ""} style={{transform : `scale(${scale}) translateX(0)`}} onClick={() => setSlide(index)} />
</div>
))}
</aside>

@ -5,6 +5,7 @@ import Mode from "../models/Mode";
const SlideContext = createContext({
slide : 0,
mode : Mode.NORMAL,
basePath : "",
setMode : () => {},
setSlide : () => {}
});

Loading…
Cancel
Save