Skip to content

Commit

Permalink
feat: local storage for projects
Browse files Browse the repository at this point in the history
  • Loading branch information
drexhage committed Dec 23, 2023
1 parent 12bf826 commit 39900d2
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 32 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
![](https://github.com/drexhage/pixel/actions/workflows/ci.yaml/badge.svg)
![](https://github.com/drexhage/pixel/actions/workflows/cd.yaml/badge.svg)
![](https://raw.githubusercontent.com/drexhage/pixel/docs-coverage/coverage/badges/flat.svg)

Expand Down
9 changes: 1 addition & 8 deletions crates/engine/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,7 @@ pub struct EngineContext {
pub(crate) idx: Option<usize>,
}

///
/// The WASM-facing interface goes here
///
// #[cfg(target_family = "wasm")]
// #[wasm_bindgen]
impl Engine {
// #[wasm_bindgen(constructor)]
pub fn new(width: u32, height: u32) -> Engine {
log::info!("Initializing session");
let size = Size { width, height };
Expand Down Expand Up @@ -149,9 +143,8 @@ impl Engine {
}
Ok(result)
} else {
// first step always has to be project/create
Err(EngineError::user_error(
"Create project has to be first step",
"First step always has to be project/create",
))
}
}
Expand Down
26 changes: 24 additions & 2 deletions crates/engine/src/wasm.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use std::collections::HashMap;

use baum::{Cursor, Tree};
use common::Size;
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};

use crate::{Engine, EngineError, Step};
use crate::{moment::Moment, Engine, EngineError, Step};

#[wasm_bindgen(start)]
fn start() {
//std::panic::set_hook(Box::new(console_error_panic_hook::hook));
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init_with_level(log::Level::Trace).expect("Failed to init logging");
}

Expand All @@ -16,6 +19,25 @@ impl Engine {
Self::new(width, height)
}

#[wasm_bindgen(js_name = reconstruct)]
pub fn _reconstruct(point: usize, val: JsValue) -> Result<Engine, EngineError> {
let mut history: Tree<Moment> =
serde_wasm_bindgen::from_value(val).map_err(EngineError::from)?;
let mut cursor = Cursor::new(&mut history, point)?;
let mut steps = vec![];
steps.push(cursor.value().data.clone());
while !cursor.is_on_root() {
cursor.go_up();
steps.push(cursor.value().data.clone());
}
steps.reverse();
let mut engine = Engine::reconstruct(&steps, HashMap::new())?;
// super danger
engine.history = history;
engine.current = point;
return Ok(engine);
}

pub fn perform_step(&mut self, val: JsValue) -> Result<Option<usize>, EngineError> {
let step: Step = serde_wasm_bindgen::from_value(val).map_err(EngineError::from)?;
self.perform(&step)?;
Expand Down
30 changes: 29 additions & 1 deletion frontend/src/lib/Dashboard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import VisualSwitch from './generic/VisualSwitch.svelte';
import ButtonColorScheme from './generic/ButtonColorScheme.svelte';
import { base } from '$app/paths';
import { onMount } from 'svelte';
skeleton.set(false);
Expand All @@ -19,7 +20,28 @@
};
}
const sizes = [
function openLocalProject(title) {
return () => {
location.href = `${base}/editor?local=${title}`;
};
}
let locals = [];
onMount(() => {
for (var i = 0, len = localStorage.length; i < len; ++i) {
let key = localStorage.key(i);
if (!key.startsWith('local/')) continue;
let localSession = JSON.parse(localStorage.getItem(key));
locals.push({
title: key.split('/')[1],
preview: localSession['preview']
});
}
locals = locals;
});
let sizes = [
{
title: 'instagram',
w: 1080,
Expand Down Expand Up @@ -75,6 +97,12 @@
/>
</div>
<div class="create-cards">
{#each locals as local}
<Button title={local.title} on:click={openLocalProject(local.title)}>
<span class="size">{local.title}</span><br />
<span class="title">local project</span>
</Button>
{/each}
{#each sizes as size}
<Button title={size.title} on:click={newProject(size.w, size.h)}>
<span class="size"
Expand Down
54 changes: 39 additions & 15 deletions frontend/src/lib/Editor.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
<script lang="ts">
import { CanvasDisplay } from '@drexhage/common-ui';
import { session, skeleton, ui } from '../store';
import { colorScheme, startListen } from '../color';
<script>
import { current, history, session, skeleton } from '../store';
import Desktop from '../lib/layout/Desktop.svelte';
import { onMount } from 'svelte';
import { base } from '$app/paths';
$: localStorage.setItem('colorscheme', $colorScheme);
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
const urlParams = new URLSearchParams(window.location.search);
const urlObj = new URL(window.location.toString());
function moveHome() {
let session = { idx: $current, history: $history, preview: null };
let key = `local/default`;
let item = localStorage.getItem(key);
if (item) {
if (confirm('Replace stored local project with the current one?')) {
localStorage.setItem(key, JSON.stringify(session));
}
}
window.location = `${base}/`;
}
// save editing history when leaving
window.onbeforeunload = function () {
return 'Are you sure?';
};
async function loadUrlAsLayer(url) {
return new Promise((resolve, reject) => {
Expand All @@ -29,19 +44,28 @@
}
let init = async () => {
let w = parseInt(urlParams.get('w')) || 2000;
let h = parseInt(urlParams.get('h')) || 1500;
urlParams.delete('w');
urlParams.delete('h');
await delay(500);
await session.init(w, h);
let w = parseInt(urlObj.searchParams.get('w')) || 2000;
let h = parseInt(urlObj.searchParams.get('h')) || 1500;
let source = urlObj.searchParams.get('local');
if (source) {
let localSession = JSON.parse(localStorage.getItem(`local/${source}`));
if (localSession) {
await session.from_history(localSession.idx, localSession.history);
} else {
await session.init(w, h);
}
} else {
urlObj.searchParams.delete('w');
urlObj.searchParams.delete('h');
window.history.pushState(undefined, undefined, urlObj.href); // remove search params
await delay(500);
await session.init(w, h);
}
skeleton.set(false);
ui.set(new CanvasDisplay(w, h, 100, 100, 10));
};
onMount(async () => {
init();
startListen();
});
</script>

<Desktop />
<Desktop {moveHome} />
1 change: 0 additions & 1 deletion frontend/src/lib/canvas/ContentCtxCanvas.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
try {
clamped = session.content_as_bytes();
} catch (e) {
console.log(e);
return;
}
let imageData = new ImageData(clamped, $ui.img_size.width, $ui.img_size.height);
Expand Down
9 changes: 6 additions & 3 deletions frontend/src/lib/layout/Desktop.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<script lang="ts">
<script>
import { blender, layers, redoable, session, ui, undoable } from '../../store';
import InteractiveCanvas from '../canvas/InteractiveCanvas.svelte';
import Button from '../generic/Button.svelte';
Expand All @@ -12,6 +12,8 @@
import Selection from '../generic/Selection.svelte';
import Dialog from '../generic/Dialog.svelte';
export let moveHome = () => {};
function base64ToArrayBuffer(base64) {
let binaryString = window.atob(base64);
let binaryLen = binaryString.length;
Expand All @@ -27,7 +29,7 @@
let canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext('2d')!;
let ctx = canvas.getContext('2d');
ctx.putImageData(image_data, 0, 0);
let base64 = canvas.toDataURL('image/png').slice('data:image/png;base64,'.length);
return base64;
Expand Down Expand Up @@ -92,6 +94,7 @@
<div id="sidebar">
<div />
<div class="top-tooling">
<Button on:click={moveHome} title="home"><i class="fa fa-home" /></Button>
<Selection
value={$blender}
on:change={(e) => session.switch_blender(e.target['value'])}
Expand Down Expand Up @@ -150,7 +153,7 @@
.top-tooling {
display: grid;
grid-template-columns: 1fr auto auto;
grid-template-columns: auto 1fr auto auto;
align-content: center;
justify-content: space-between;
gap: 5px;
Expand Down
14 changes: 12 additions & 2 deletions frontend/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ async function createSession() {
let prev;

function update() {
blender.set(engine.blender);
layers.set(engine.content);
history.set(engine.history);
current.set(engine.current);
Expand All @@ -85,7 +86,7 @@ async function createSession() {
}

return {
init: async function (w: number, h: number) {
init: async function (w: number, h: number): Promise<void> {
await init_ui();
wasm = await init_engine();
width = w;
Expand All @@ -104,7 +105,16 @@ async function createSession() {
if (idx) {
focused.set([idx]);
}
blender.set(engine.blender);
ui.set(new CanvasDisplay(w, h, 100, 100, 10));
update();
},
from_history: async function (idx: number, his: Tree<any>): Promise<void> {
await init_ui();
wasm = await init_engine();
engine = Engine.reconstruct(idx, his);
width = engine.size.width;
height = engine.size.height;
ui.set(new CanvasDisplay(width, height, 100, 100, 10));
update();
},
switch_blender: function (type) {
Expand Down

0 comments on commit 39900d2

Please sign in to comment.