Skip to content

Commit

Permalink
Convert components to JSX
Browse files Browse the repository at this point in the history
  • Loading branch information
caleb531 committed Aug 21, 2024
1 parent 66bad4f commit aff5b7c
Show file tree
Hide file tree
Showing 22 changed files with 805 additions and 694 deletions.
30 changes: 13 additions & 17 deletions scripts/components/app-header.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
import m from 'mithril';

class AppHeaderComponent {

view() {
return m('.app-header', [
m('h1', 'Flip Book'),
m('.app-header-mentions', [
m('span.app-header-mention', [
'By ',
m('a[href="https://calebevans.me/"]', 'Caleb Evans'),
'.'
]),
m('span.app-header-mention', [
'For my friend and brother, Bill.'
])
])
]);
return (
<div className="app-header">
<h1>Flip Book</h1>
<div className="app-header-mentions">
<span className="app-header-mention">
By <a href="https://calebevans.me/">Caleb Evans</a>.
</span>
<span className="app-header-mention">
For my friend and brother, Bill.
</span>
</div>
</div>
);
}

}

export default AppHeaderComponent;
54 changes: 25 additions & 29 deletions scripts/components/app.jsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
import m from 'mithril';
import App from '../models/app.js';
import UpdateNotificationComponent from './update-notification.jsx';
import AppHeaderComponent from './app-header.jsx';
import StoryComponent from './story.jsx';
import StorageUpgraderComponent from './storage-upgrader.jsx';
import m from "mithril";
import App from "../models/app.js";
import UpdateNotificationComponent from "./update-notification.jsx";
import AppHeaderComponent from "./app-header.jsx";
import StoryComponent from "./story.jsx";
import StorageUpgraderComponent from "./storage-upgrader.jsx";

class AppComponent {

oninit() {
App.restore().then((app) => {
this.app = app;
m.redraw();
});
}

oncreate({dom}) {
oncreate({ dom }) {
dom.focus();
}

async navigateFramesViaKeyboard(event) {
let story = await this.app.selectedStory;
if (event.key === 'ArrowLeft' && !story.playing) {
if (event.key === "ArrowLeft" && !story.playing) {
story.selectPreviousFrame();
await story.save();
} else if (event.key === 'ArrowRight' && !story.playing) {
} else if (event.key === "ArrowRight" && !story.playing) {
story.selectNextFrame();
await story.save();
} else if (event.key === ' ') {
} else if (event.key === " ") {
event.preventDefault();
if (story.playing) {
story.pause();
Expand All @@ -39,25 +38,22 @@ class AppComponent {
}

view() {
return m('div.app[tabindex=-1]', {
onkeydown: (event) => this.navigateFramesViaKeyboard(event)
}, [

// The UpdateNotificationComponent manages its own visibility
m(UpdateNotificationComponent),

m(StorageUpgraderComponent),

m(AppHeaderComponent),

this.app?.selectedStory ? m(StoryComponent, {
app: this.app,
story: this.app.selectedStory
}) : null

]);
return (
<div
className="app"
tabIndex="-1"
onkeydown={(event) => this.navigateFramesViaKeyboard(event)}
>
{/* The UpdateNotificationComponent manages its own visibility */}
<UpdateNotificationComponent />
<StorageUpgraderComponent />
<AppHeaderComponent />
{this.app?.selectedStory ? (
<StoryComponent app={this.app} story={this.app.selectedStory} />
) : null}
</div>
);
}

}

export default AppComponent;
76 changes: 49 additions & 27 deletions scripts/components/control.jsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,56 @@
import m from 'mithril';
import clsx from 'clsx';
import PanelComponent from './panel.jsx';
import clsx from "clsx";
import PanelComponent from "./panel.jsx";

class ControlComponent {

view({attrs: {id, title, icon = null, label = null, action = null, panel = null, panelPosition = 'top'}}) {
return m(`div`, {
class: clsx('control', `control-${id}`, {'control-has-label': label})
}, [
panel ? m(PanelComponent, {id, position: panelPosition}, panel) : null,
m('button.control-button', {
title,
onclick: ({target}) => {
if (panel) {
PanelComponent.togglePanel(id);
} else if (action) {
// Do not close the panel where the clicked control resides
if (!target.closest('.panel')) {
PanelComponent.closeAllPanels();
view({
attrs: {
id,
title,
icon = null,
label = null,
action = null,
panel = null,
panelPosition = "top",
},
}) {
return (
<div
className={clsx("control", `control-${id}`, {
"control-has-label": label,
})}
>
{panel ? (
<PanelComponent id={id} position={panelPosition}>
{panel}
</PanelComponent>
) : null}
<button
className="control-button"
title={title}
onclick={({ target }) => {
if (panel) {
PanelComponent.togglePanel(id);
} else if (action) {
// Do not close the panel where the clicked control resides
if (!target.closest(".panel")) {
PanelComponent.closeAllPanels();
}
action();
}
action();
}
}
}, [
icon ? m('img.control-icon', {src: `icons/${icon}.svg`, alt: title}) : null,
label ? m('span.control-label', label) : null
])
]);
}}
>
{icon ? (
<img
className="control-icon"
src={`icons/${icon}.svg`}
alt={title}
/>
) : null}
{label ? <span className="control-label">{label}</span> : null}
</button>
</div>
);
}

}

export default ControlComponent;
60 changes: 34 additions & 26 deletions scripts/components/drawing-area.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import m from 'mithril';
import FrameComponent from './frame.jsx';
import FrameComponent from "./frame.jsx";

class DrawingAreaComponent extends FrameComponent {

oninit({attrs: {story, frame, drawingEnabled = true}}) {
oninit({ attrs: { story, frame, drawingEnabled = true } }) {
this.story = story;
super.oninit({attrs: {frame}});
super.oninit({ attrs: { frame } });
this.drawingEnabled = drawingEnabled;
}

oncreate({dom}) {
super.oncreate({dom});
oncreate({ dom }) {
super.oncreate({ dom });
}

onupdate({attrs: {story, frame, drawingEnabled = true}}) {
onupdate({ attrs: { story, frame, drawingEnabled = true } }) {
this.story = story;
this.drawingEnabled = drawingEnabled;
super.onupdate({attrs: {frame}});
super.onupdate({ attrs: { frame } });
}

handleDrawStart(event, pageX, pageY) {
Expand All @@ -30,7 +28,7 @@ class DrawingAreaComponent extends FrameComponent {
let startX = (pageX - this.canvasOffsetLeft) * this.canvasScaleFactor;
let startY = (pageY - this.canvasOffsetTop) * this.canvasScaleFactor;
this.frame.startNewGroup({
styles: Object.assign({}, this.story.frameStyles)
styles: Object.assign({}, this.story.frameStyles),
});
this.frame.addPoint(startX, startY);
this.lastX = startX;
Expand Down Expand Up @@ -68,13 +66,21 @@ class DrawingAreaComponent extends FrameComponent {

handleTouchStart(event) {
if (event.changedTouches?.length > 0) {
this.handleDrawStart(event, event.changedTouches[0].pageX, event.changedTouches[0].pageY);
this.handleDrawStart(
event,
event.changedTouches[0].pageX,
event.changedTouches[0].pageY,
);
}
}

handleTouchMove(event) {
if (event.changedTouches?.length > 0) {
this.handleDrawMove(event, event.changedTouches[0].pageX, event.changedTouches[0].pageY);
this.handleDrawMove(
event,
event.changedTouches[0].pageX,
event.changedTouches[0].pageY,
);
}
}

Expand Down Expand Up @@ -109,20 +115,22 @@ class DrawingAreaComponent extends FrameComponent {
}

view() {
return m('canvas.selected-frame', {
width: FrameComponent.width,
height: FrameComponent.height,
// Touch events
ontouchstart: (event) => this.handleTouchStart(event),
ontouchmove: (event) => this.handleTouchMove(event),
ontouchend: (event) => this.handleTouchEnd(event),
// Mouse events
onmousedown: (event) => this.handleMouseDown(event),
onmousemove: (event) => this.handleMouseMove(event),
onmouseup: (event) => this.handleMouseUp(event),
onmouseout: (event) => this.handleMouseUp(event)
});
return (
<canvas
className="selected-frame"
width={FrameComponent.width}
height={FrameComponent.height}
// Touch events
ontouchstart={(event) => this.handleTouchStart(event)}
ontouchmove={(event) => this.handleTouchMove(event)}
ontouchend={(event) => this.handleTouchEnd(event)}
// Mouse events
onmousedown={(event) => this.handleMouseDown(event)}
onmousemove={(event) => this.handleMouseMove(event)}
onmouseup={(event) => this.handleMouseUp(event)}
onmouseout={(event) => this.handleMouseUp(event)}
/>
);
}

}
export default DrawingAreaComponent;
74 changes: 44 additions & 30 deletions scripts/components/export-gif.jsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,50 @@
import m from 'mithril';
import clsx from 'clsx';
import ControlComponent from './control.jsx';
import ProgressBarComponent from './progress-bar.jsx';
import clsx from "clsx";
import ControlComponent from "./control.jsx";
import ProgressBarComponent from "./progress-bar.jsx";

class ExportGifComponent {

view({attrs: {isExportingGif, exportProgress, isGifExportFinished, exportedImageUrl, abort}}) {
return m('div', {
class: clsx('export-gif-screen', {'visible': isExportingGif || isGifExportFinished})
}, [
m(ControlComponent, {
id: 'close-export-gif-overlay',
title: isGifExportFinished ? 'Close overlay' : 'Abort GIF export',
icon: 'close',
action: () => abort()
}),
m('div.export-gif-overlay'),
m('div.export-gif-heading', exportedImageUrl ?
'GIF Generated!' :
'Generating GIF...'),
m('p.export-gif-message', exportedImageUrl ?
'Right-click the image and choose "Save Image As..." to download.' :
''),
exportedImageUrl ? m('img.exported-image', {
src: exportedImageUrl,
alt: 'Exported GIF'
}) : m(ProgressBarComponent, {
progress: exportProgress
})
]);
view({
attrs: {
isExportingGif,
exportProgress,
isGifExportFinished,
exportedImageUrl,
abort,
},
}) {
return (
<div
className={clsx("export-gif-screen", {
visible: isExportingGif || isGifExportFinished,
})}
>
<ControlComponent
id="close-export-gif-overlay"
title={isGifExportFinished ? "Close overlay" : "Abort GIF export"}
icon="close"
action={() => abort()}
/>
<div className="export-gif-overlay" />
<div className="export-gif-heading">
{exportedImageUrl ? "GIF Generated!" : "Generating GIF..."}
</div>
<p className="export-gif-message">
{exportedImageUrl
? 'Right-click the image and choose "Save Image As..." to download.'
: ""}
</p>
{exportedImageUrl ? (
<img
className="exported-image"
src={exportedImageUrl}
alt="Exported GIF"
/>
) : (
<ProgressBarComponent progress={exportProgress} />
)}
</div>
);
}

}

export default ExportGifComponent;
Loading

0 comments on commit aff5b7c

Please sign in to comment.