Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Cargo
# will have compiled files and executables
**/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

.vscode/

**/dist/
node_modules/

# Local frontend tooling binaries
frontend/tools/
12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[workspace]
resolver = "3"
members = [
"frontend",
"shared",
]

[workspace.lints.clippy]
all = "warn"
pedantic = "warn"
nursery = "warn"
cargo = "warn"
22 changes: 22 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

The MIT License (MIT)

Copyright (c) 2026 Stoffl

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
76 changes: 75 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,75 @@
# BrickTutorialCreator
```md
# BrickCreator

BrickCreator is a responsive web application built for the Catrobat Pocket Code community, especially educators and users who create learning materials for Pocket Code.

The website works on both desktop and mobile devices and is included in the Catrobat repository ecosystem.

## About

BrickCreator allows users to create, edit, and import Pocket Code user bricks, then export them into multiple file formats for use in:

- Presentations
- Tutorials
- Worksheets
- Teaching materials
- Documentation

Supported import formats include:

- JSON

Supported export formats include:

- PNG
- SVG
- JSON

## Features

- Create custom user bricks visually
- Import existing brick data
- Export bricks as PNG, SVG, or JSON
- Mobile-friendly and desktop-friendly design
- Easy to use for teachers and beginners

## Purpose

BrickCreator was developed to simplify the creation of educational content for Pocket Code. Instead of manually designing and capturing screenshots bricks for slides or tutorials, users can generate high-quality assets directly in the browser.

## About Catrobat

Catrobat is an open-source platform with contributors from all over the world.

Learn more: https://catrobat.org/about

## Compatibility

BrickCreator works in modern web browsers on:

- Desktop devices
- Tablets
- Smartphones

## Running BrickCreator

To run the project locally, make sure you have Rust and Trunk installed.

1. Change into the frontend directory:
`cd frontend`
2. Start the development server:
`trunk serve`
3. Open BrickCreator in your browser at:
`http://127.0.0.1:8080`

If you want to run it from the repository root instead, you can use:
`trunk serve --config frontend/Trunk.toml`

## Contributing

Contributions, ideas, and improvements are welcome through the Catrobat project.

## License

!!TODO Issue #13!!
```
20 changes: 20 additions & 0 deletions frontend/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "frontend"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
shared = { path = "../shared" }
serde_json = "1.0.149"
base64 = "0.22.1"

wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
web-sys = { version = "0.3", features = ["Window", "Document", "Element", "EventTarget", "File", "FileList", "FileReader", "HtmlElement", "HtmlAnchorElement", "HtmlCanvasElement", "CanvasRenderingContext2d", "HtmlImageElement", "HtmlInputElement", "HtmlTextAreaElement", "DragEvent", "DataTransfer", "Blob", "BlobPropertyBag", "Url", "ResizeObserver", "ResizeObserverEntry", "TouchEvent", "TouchList", "Touch"] }
js-sys = "0.3"
console_error_panic_hook = "0.1"
yew = { version = "0.23", features = ["csr"] }
gloo = { version = "0.11", features = ["file"] }
3 changes: 3 additions & 0 deletions frontend/Trunk.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build]
target = "index.html"
dist = "dist"
63 changes: 63 additions & 0 deletions frontend/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use std::{
env, fs,
path::{Path, PathBuf},
};

fn collect_json_files(root: &Path) -> std::io::Result<Vec<PathBuf>> {
let mut files = Vec::new();
let mut stack = vec![root.to_path_buf()];

while let Some(dir) = stack.pop() {
for entry in fs::read_dir(&dir)? {
let entry = entry?;
let path = entry.path();
let ty = entry.file_type()?;
if ty.is_dir() {
stack.push(path);
} else if ty.is_file() && path.extension().is_some_and(|e| e == "json") {
files.push(path);
}
}
}

Ok(files)
}

fn main() {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
let bricks_root = manifest_dir.join("../utils/output");

println!("cargo:rerun-if-changed={}", bricks_root.display());

let mut files = collect_json_files(&bricks_root).expect("failed to read ../utils/output");
files.sort();
for file in &files {
println!("cargo:rerun-if-changed={}", file.display());
}

let mut out = String::new();
out.push_str("// @generated by frontend/build.rs\n");
out.push_str("pub const BRICKS: &[(&str, &str)] = &[\n");

for file in &files {
let rel = file
.strip_prefix(&bricks_root)
.expect("strip_prefix bricks_root")
.to_string_lossy()
.replace('\\', "/");
let rel_lit = format!("{rel:?}");

out.push_str(" (");
out.push_str(&rel_lit);
out.push_str(
", include_str!(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/../utils/output/\", ",
);
out.push_str(&rel_lit);
out.push_str("))),\n");
}

out.push_str("];\n");

let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR"));
fs::write(out_dir.join("brick_catalog.rs"), out).expect("write brick_catalog.rs");
}
11 changes: 11 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>BrickCreator</title>
<link data-trunk rel="css" href="style.css" />
<link data-trunk rel="rust" />
</head>
<body></body>
</html>
Loading