From 96a8519c9c8e70755779864f48f37ac128474ddc Mon Sep 17 00:00:00 2001 From: Cyrus Yiu Date: Fri, 17 Jul 2026 20:15:43 -0400 Subject: [PATCH 1/7] WE'RE REWRITE THIS --- examples/Racers icon.png | Bin 4443 -> 0 bytes examples/Racers to Electron.yaml | 31 -- examples/Racers to Tauri.yaml | 31 -- examples/Racers to static files.yaml | 31 -- src/convert/__init__.py | 0 src/convert/mkcd_to_website/__init__.py | 0 src/convert/mkcd_to_website/config.py | 135 -------- src/convert/mkcd_to_website/source.py | 67 ---- src/convert/mkcd_to_website/website.py | 153 --------- src/convert/website_to_electron/__init__.py | 0 src/convert/website_to_electron/electron.py | 122 ------- src/convert/website_to_tauri/__init__.py | 0 src/convert/website_to_tauri/tauri.py | 127 ------- src/main.py | 160 +-------- src/templates/electron_files/README.md | 6 - src/templates/electron_files/forge.config.js | 65 ---- src/templates/electron_files/package.json | 36 -- src/templates/electron_files/src/main.js | 73 ---- src/templates/electron_files/src/preload.js | 2 - src/templates/electron_files/src/renderer.js | 29 -- .../electron_files/webpack.main.config.js | 11 - .../electron_files/webpack.renderer.config.js | 27 -- src/templates/electron_files/webpack.rules.js | 35 -- src/templates/tauri_files/.gitignore | 24 -- src/templates/tauri_files/README.md | 6 - src/templates/tauri_files/package.json | 12 - .../tauri_files/src-tauri/.gitignore | 7 - .../tauri_files/src-tauri/Cargo.toml | 25 -- src/templates/tauri_files/src-tauri/build.rs | 3 - .../src-tauri/capabilities/default.json | 10 - .../tauri_files/src-tauri/icons/.keep | 0 .../tauri_files/src-tauri/src/lib.rs | 14 - .../tauri_files/src-tauri/src/main.rs | 6 - .../tauri_files/src-tauri/tauri.conf.json | 31 -- src/templates/website_files/.prettierignore | 1 - src/templates/website_files/README.md | 6 - src/templates/website_files/eslint.config.js | 43 --- src/templates/website_files/index.html | 13 - src/templates/website_files/package.json | 39 --- src/templates/website_files/src/App.css | 14 - src/templates/website_files/src/App.tsx | 322 ------------------ .../website_files/src/gameConfiguration.ts | 54 --- src/templates/website_files/src/global.d.ts | 1 - src/templates/website_files/src/main.tsx | 24 -- .../website_files/src/utils/position.ts | 38 --- .../website_files/src/utils/toasts.ts | 37 -- src/templates/website_files/src/vite-env.d.ts | 1 - src/templates/website_files/tsconfig.app.json | 27 -- src/templates/website_files/tsconfig.json | 7 - .../website_files/tsconfig.node.json | 25 -- src/templates/website_files/vite.config.ts | 8 - src/utils/cmd.py | 38 --- src/utils/filesystem.py | 49 --- 53 files changed, 1 insertion(+), 2025 deletions(-) delete mode 100644 examples/Racers icon.png delete mode 100644 examples/Racers to Electron.yaml delete mode 100644 examples/Racers to Tauri.yaml delete mode 100644 examples/Racers to static files.yaml delete mode 100644 src/convert/__init__.py delete mode 100644 src/convert/mkcd_to_website/__init__.py delete mode 100644 src/convert/mkcd_to_website/config.py delete mode 100644 src/convert/mkcd_to_website/source.py delete mode 100644 src/convert/mkcd_to_website/website.py delete mode 100644 src/convert/website_to_electron/__init__.py delete mode 100644 src/convert/website_to_electron/electron.py delete mode 100644 src/convert/website_to_tauri/__init__.py delete mode 100644 src/convert/website_to_tauri/tauri.py delete mode 100644 src/templates/electron_files/README.md delete mode 100644 src/templates/electron_files/forge.config.js delete mode 100644 src/templates/electron_files/package.json delete mode 100644 src/templates/electron_files/src/main.js delete mode 100644 src/templates/electron_files/src/preload.js delete mode 100644 src/templates/electron_files/src/renderer.js delete mode 100644 src/templates/electron_files/webpack.main.config.js delete mode 100644 src/templates/electron_files/webpack.renderer.config.js delete mode 100644 src/templates/electron_files/webpack.rules.js delete mode 100644 src/templates/tauri_files/.gitignore delete mode 100644 src/templates/tauri_files/README.md delete mode 100644 src/templates/tauri_files/package.json delete mode 100644 src/templates/tauri_files/src-tauri/.gitignore delete mode 100644 src/templates/tauri_files/src-tauri/Cargo.toml delete mode 100644 src/templates/tauri_files/src-tauri/build.rs delete mode 100644 src/templates/tauri_files/src-tauri/capabilities/default.json delete mode 100644 src/templates/tauri_files/src-tauri/icons/.keep delete mode 100644 src/templates/tauri_files/src-tauri/src/lib.rs delete mode 100644 src/templates/tauri_files/src-tauri/src/main.rs delete mode 100644 src/templates/tauri_files/src-tauri/tauri.conf.json delete mode 100644 src/templates/website_files/.prettierignore delete mode 100644 src/templates/website_files/README.md delete mode 100644 src/templates/website_files/eslint.config.js delete mode 100644 src/templates/website_files/index.html delete mode 100644 src/templates/website_files/package.json delete mode 100644 src/templates/website_files/src/App.css delete mode 100644 src/templates/website_files/src/App.tsx delete mode 100644 src/templates/website_files/src/gameConfiguration.ts delete mode 100644 src/templates/website_files/src/global.d.ts delete mode 100644 src/templates/website_files/src/main.tsx delete mode 100644 src/templates/website_files/src/utils/position.ts delete mode 100644 src/templates/website_files/src/utils/toasts.ts delete mode 100644 src/templates/website_files/src/vite-env.d.ts delete mode 100644 src/templates/website_files/tsconfig.app.json delete mode 100644 src/templates/website_files/tsconfig.json delete mode 100644 src/templates/website_files/tsconfig.node.json delete mode 100644 src/templates/website_files/vite.config.ts delete mode 100644 src/utils/cmd.py delete mode 100644 src/utils/filesystem.py diff --git a/examples/Racers icon.png b/examples/Racers icon.png deleted file mode 100644 index 7731c2aa74648e328773eb5f1be652350b110fc4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4443 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 diff --git a/examples/Racers to Electron.yaml b/examples/Racers to Electron.yaml deleted file mode 100644 index 60df016..0000000 --- a/examples/Racers to Electron.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Example configuration file for MakeCode Arcade to App to compile to an executable - -name: Racers -description: "Enjoy the high-speed thrills of car racing in MakeCode Arcade! - For the MakeCode Arcade Mini Game Jam #3." -author: UnsignedArduino -version: 1.3.2 -# This is what the window title will be -# This will also be used for the executable file name for Electron outputs -# You can use {NAME} or {VERSION} or {AUTHOR} to substitute the correct values -title: "{NAME} v{VERSION}" - -# Game source - where the game code is located - this will download / copy everything -# Can be a GitHub repository (.git ending is optional) that specifies something to check out, -# a MakeCode Arcade share link, (ex. https://arcade.makecode.com/84426-33815-03715-00484) -# or a path (ex. F:/Racers) -#source: -# url: https://github.com/UnsignedArduino/Racers -# checkout: master # Could be a branch, tag, commit hash, etc. (it's passed to `git checkout` directly) -source: https://arcade.makecode.com/84426-33815-03715-00484 -#source: F:/Racers - -# Game icon - this will be the icon of the tab or executable -# Either absolute path to a file, a relative path from this file, or a URL -#icon: Racers icon.png -icon: https://raw.githubusercontent.com/UnsignedArduino/MakeCode-Arcade-to-App/refs/heads/main/examples/Racers%20icon.png - -# Output format - whether to output static files, an Electron app, or a Tauri app. -# output: static -output: electron -# output: tauri diff --git a/examples/Racers to Tauri.yaml b/examples/Racers to Tauri.yaml deleted file mode 100644 index dc2741a..0000000 --- a/examples/Racers to Tauri.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Example configuration file for MakeCode Arcade to App to compile to an executable - -name: Racers -description: "Enjoy the high-speed thrills of car racing in MakeCode Arcade! - For the MakeCode Arcade Mini Game Jam #3." -author: UnsignedArduino -version: 1.3.2 -# This is what the window title will be -# This will also be used for the executable file name for Electron outputs -# You can use {NAME} or {VERSION} or {AUTHOR} to substitute the correct values -title: "{NAME} v{VERSION}" - -# Game source - where the game code is located - this will download / copy everything -# Can be a GitHub repository (.git ending is optional) that specifies something to check out, -# a MakeCode Arcade share link, (ex. https://arcade.makecode.com/84426-33815-03715-00484) -# or a path (ex. F:/Racers) -#source: -# url: https://github.com/UnsignedArduino/Racers -# checkout: master # Could be a branch, tag, commit hash, etc. (it's passed to `git checkout` directly) -source: https://arcade.makecode.com/84426-33815-03715-00484 -#source: F:/Racers - -# Game icon - this will be the icon of the tab or executable -# Either absolute path to a file, a relative path from this file, or a URL -#icon: Racers icon.png -icon: https://raw.githubusercontent.com/UnsignedArduino/MakeCode-Arcade-to-App/refs/heads/main/examples/Racers%20icon.png - -# Output format - whether to output static files, an Electron app, or a Tauri app. -# output: static -# output: electron -output: tauri diff --git a/examples/Racers to static files.yaml b/examples/Racers to static files.yaml deleted file mode 100644 index 1e6443b..0000000 --- a/examples/Racers to static files.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Example configuration file for MakeCode Arcade to App to compile to an executable - -name: Racers -description: "Enjoy the high-speed thrills of car racing in MakeCode Arcade! - For the MakeCode Arcade Mini Game Jam #3." -author: UnsignedArduino -version: 1.3.2 -# This is what the window title will be -# This will also be used for the executable file name for Electron outputs -# You can use {NAME} or {VERSION} or {AUTHOR} to substitute the correct values -title: "{NAME} v{VERSION}" - -# Game source - where the game code is located - this will download / copy everything -# Can be a GitHub repository (.git ending is optional) that specifies something to check out, -# a MakeCode Arcade share link, (ex. https://arcade.makecode.com/84426-33815-03715-00484) -# or a path (ex. F:/Racers) -#source: -# url: https://github.com/UnsignedArduino/Racers -# checkout: master # Could be a branch, tag, commit hash, etc. (it's passed to `git checkout` directly) -source: https://arcade.makecode.com/84426-33815-03715-00484 -#source: F:/Racers - -# Game icon - this will be the icon of the tab or executable -# Either absolute path to a file, a relative path from this file, or a URL -#icon: Racers icon.png -icon: https://raw.githubusercontent.com/UnsignedArduino/MakeCode-Arcade-to-App/refs/heads/main/examples/Racers%20icon.png - -# Output format - whether to output static files, an Electron app, or a Tauri app. -output: static -# output: electron -# output: tauri diff --git a/src/convert/__init__.py b/src/convert/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/convert/mkcd_to_website/__init__.py b/src/convert/mkcd_to_website/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/convert/mkcd_to_website/config.py b/src/convert/mkcd_to_website/config.py deleted file mode 100644 index 2d01b3c..0000000 --- a/src/convert/mkcd_to_website/config.py +++ /dev/null @@ -1,135 +0,0 @@ -import logging -from dataclasses import dataclass -from enum import Enum -from pathlib import Path -from typing import Optional -from urllib.parse import urlparse - -import yaml - -from utils.logger import create_logger - -logger = create_logger(name=__name__, level=logging.INFO) - - -class SourceType(Enum): - GITHUB = "github" - SHARE_LINK = "share_link" - PATH = "path" - - -class IconSourceType(Enum): - PATH = "path" - URL = "url" - - -class OutputType(Enum): - STATIC = "static" - ELECTRON = "electron" - TAURI = "tauri" - - -@dataclass -class Config: - """ - Configuration class. - """ - name: str - description: str - author: str - version: str - title: str - - source: str - source_type: SourceType - source_checkout: Optional[str] = None # For GitHub sources - - icon: Optional[Path | str] = None - icon_source_type: Optional[IconSourceType] = None - - output: OutputType = OutputType.STATIC - - -# https://stackoverflow.com/a/36283503/10291933 -def is_valid_url(url, qualifying=('scheme', 'netloc')): - tokens = urlparse(url) - return all(getattr(tokens, qualifying_attr) - for qualifying_attr in qualifying) - - -def determine_source_type(source: str | dict) -> SourceType: - """ - Determines the source type based on the provided source string. - - :param source: The source string or dictionary. - :return: The SourceType enum value. - """ - # We could do more checks for validity / strictness here - if type(source) is not str: - # Should have url and checkout - return SourceType.GITHUB - elif is_valid_url(source): - return SourceType.SHARE_LINK - else: - return SourceType.PATH - - -def determine_icon_source_type(icon: str) -> IconSourceType: - """ - Determines the icon source type based on the provided icon string. - - :param icon: The icon string. - :return: The IconSourceType enum value. - """ - # We could do more checks for validity / strictness here - if is_valid_url(icon): - return IconSourceType.URL - else: - return IconSourceType.PATH - - -def parse_config(yaml_text: str, cwd: Path) -> Config: - """ - Parses the YAML configuration file and returns a Config object. - - :param yaml_text: The YAML configuration text. - :param cwd: The current working directory to resolve relative paths. - :return: A Config object. - """ - logger.debug(f"Parsing YAML configuration") - result = yaml.safe_load(yaml_text) - - src = result.get("source") - src_type = determine_source_type(src) - logger.debug(f"Determined source type for {src} is {src_type}") - src_checkout = None - if type(src) is not str: - src_checkout = src.get("checkout") - src = src.get("url") - logger.debug(f"Complex GitHub source detected - will checkout {src_checkout} " - f"for url {src}") - - icon = result.get("icon") - icon_source_type = None if icon is None else determine_icon_source_type(icon) - if icon_source_type == IconSourceType.PATH: - icon = Path(icon) - if not icon.is_absolute(): - icon = cwd / icon - logger.debug(f"Determined icon source type for {icon} is {icon_source_type}") - - config = Config( - name=result.get("name"), - description=result.get("description"), - author=result.get("author"), - version=result.get("version"), - title=result.get("title"), - source=src, - source_type=src_type, - source_checkout=src_checkout, - icon=icon, - icon_source_type=icon_source_type, - output=OutputType(result.get("output", "static").lower()) - ) - config.title = config.title.format(NAME=config.name, VERSION=config.version, AUTHOR=config.author) - logger.debug(f"Parsed configuration: {config}") - return config diff --git a/src/convert/mkcd_to_website/source.py b/src/convert/mkcd_to_website/source.py deleted file mode 100644 index d5190c3..0000000 --- a/src/convert/mkcd_to_website/source.py +++ /dev/null @@ -1,67 +0,0 @@ -import logging -import shutil -from pathlib import Path -from typing import Optional - -from convert.mkcd_to_website.config import Config, SourceType -from utils.cmd import run_command, run_shell_command -from utils.logger import create_logger - -logger = create_logger(name=__name__, level=logging.INFO) - - -def download_source(config: Config, cwd: Path, - no_cache: Optional[bool] = False) -> Path: - """ - Downloads the source code based on the provided configuration. - - :param config: The configuration object containing source information. - :param cwd: The current working directory where the source code folder will be - downloaded. - :param no_cache: If True, forces a fresh download of the source code. - :return: The path to the downloaded source code. - """ - source_code_path = cwd / f"{config.name} source" - if no_cache: - logger.debug("Checking for existing source code to remove") - if source_code_path.exists(): - logger.debug(f"Removing {source_code_path}") - try: - shutil.rmtree(source_code_path) - except PermissionError as e: - logger.error(e) - logger.error("Permission denied. If it's a .git object, you may need " - "to delete it with admin/superuser privileges.") - raise e - elif source_code_path.exists(): - logger.debug(f"Source code already exists at {source_code_path}") - if config.source_type == SourceType.GITHUB: - logger.debug("Checking for updates") - run_command(["git", "checkout", config.source_checkout], - cwd=source_code_path) - run_command(["git", "pull"], cwd=source_code_path) - return source_code_path - if config.source_type == SourceType.GITHUB: - logger.info(f"Downloading source from GitHub") - # Assume it's `git clone`able - run_command(["git", "clone", config.source, source_code_path], cwd=cwd) - logger.info(f"Checking out {config.source_checkout}") - run_command(["git", "checkout", config.source_checkout], cwd=source_code_path) - elif config.source_type == SourceType.SHARE_LINK: - logger.info(f"Downloading source from share link") - source_code_path.mkdir(parents=True, exist_ok=True) - run_shell_command(f"npx mkc download {config.source}", cwd=source_code_path) - elif config.source_type == SourceType.PATH: - logger.info(f"Copying source from path") - source_code_path.mkdir(parents=True, exist_ok=True) - # Copy the contents of the source directory to the source_code_path - source_path = Path(config.source) - for item in source_path.iterdir(): - if item.is_dir(): - shutil.copytree(item, source_code_path / item.name) - else: - shutil.copy2(item, source_code_path / item.name) - else: - raise ValueError(f"Unknown source type {config.source_type}") - logger.debug(f"Source code path: {source_code_path}") - return source_code_path diff --git a/src/convert/mkcd_to_website/website.py b/src/convert/mkcd_to_website/website.py deleted file mode 100644 index 630c0df..0000000 --- a/src/convert/mkcd_to_website/website.py +++ /dev/null @@ -1,153 +0,0 @@ -import json -import logging -import shutil -from io import BytesIO -from pathlib import Path -from typing import Callable - -import requests -from PIL import Image -from bs4 import BeautifulSoup - -from convert.mkcd_to_website.config import Config, IconSourceType, SourceType -from utils.cmd import run_shell_command -from utils.logger import create_logger - -logger = create_logger(name=__name__, level=logging.INFO) - - -def generate_website(config: Config, prj_name: str, template_dir: Path, cwd: Path, - bin_js_path: Path): - """ - Generate the website by initializing a React TS Vite project, copying the necessary - files, and substituting the correct values in. - - :param config: The configuration object containing the project information. - :param prj_name: The name of the project. - :param template_dir: The directory containing the template files. - :param cwd: The current working directory where the project will be created. - :param bin_js_path: The path to the binary.js file. - """ - logger.debug(f"Creating React TS Vite project for {prj_name}") - # Initialize a React TS Vite project - if (cwd / prj_name).exists(): - logger.debug(f"Project {prj_name} already exists, continuing...") - else: - run_shell_command(f"yarn create vite {prj_name} -t react-ts --no-interactive --no-rolldown", cwd=cwd) - # Start copying files from template - old_dir = template_dir - new_dir = cwd / prj_name - - def copy_template(file_name: str, callback: Callable[[str], str] = lambda x: x): - (new_dir / file_name).write_text(callback((old_dir / file_name).read_text())) - - logger.debug(f"Copying website files from {old_dir} to {new_dir}") - # Copy index.html and substitute the title - copy_template("index.html", lambda x: x.format(TITLE=config.title)) - # Modify package.json - package_json = json.loads((old_dir / "package.json").read_text()) - package_json["name"] = prj_name - package_json["version"] = config.version - package_json["description"] = config.description - package_json["author"] = config.author - package_json["scripts"] = { - "dev": "vite", - "lint": "eslint .", - "writeLint": "eslint --fix .", - "format": "prettier --check .", - "writeFormat": "prettier --write .", - "build": "tsc -b && vite build", - "preview": "vite preview" - } - (new_dir / "package.json").write_text(json.dumps(package_json, indent=2)) - # Queue dependencies to add (these will be "yarn add"ed) - dependencies = ["react-toastify"] - dev_dependencies = ["eslint-plugin-react-dom", "eslint-plugin-react-x", "prettier"] - # Copy README.md - copy_template("README.md", - lambda x: x.format(WEBSITE_NAME=prj_name, - SOURCE=f"{config.source} @ {config.source_checkout}" if config.source_type == SourceType.GITHUB else config.source)) - # Copy more files - for file_name in ("vite.config.ts", "eslint.config.js", ".prettierignore", - "tsconfig.json", - "tsconfig.app.json", "tsconfig.node.json"): - copy_template(file_name) - # yarn - run_shell_command("yarn", cwd=new_dir) - # yarn add stuff - run_shell_command(f"yarn add {" ".join(dependencies)}", cwd=new_dir) - run_shell_command(f"yarn add {" ".join(dev_dependencies)} --dev", cwd=new_dir) - # Clear public directory - if (new_dir / "public").exists(): - shutil.rmtree(new_dir / "public") - (new_dir / "public").mkdir(parents=True, exist_ok=True) - # Clear src/assets directory - if (new_dir / "src" / "assets").exists(): - shutil.rmtree(new_dir / "src" / "assets") - # Copy src directory - shutil.copytree(old_dir / "src", new_dir / "src", dirs_exist_ok=True) - game_config_ts_path = new_dir / "src" / "gameConfiguration.ts" - logger.debug(f"gameConfiguration.ts at {game_config_ts_path}") - # Copy binary.js - logger.debug(f"Copying binary.js from {bin_js_path}") - shutil.copy(bin_js_path, new_dir / "public" / "binary.js") - # Download https://trg-arcade.userpxt.io/---simulator - logger.debug("Downloading simulator files") - res = requests.get("https://trg-arcade.userpxt.io/---simulator") - if res.ok: - sim_html = res.text - else: - raise Exception(f"Failed to download simulator: {res.status_code} {res.reason}") - # Analyze simulator HTML for required CSS and JS files - logger.debug("Analyzing simulator HTML for required CSS and JS files") - soup = BeautifulSoup(sim_html, features="html.parser") - css_links = soup.find_all("link", rel="stylesheet") - js_scripts = soup.find_all("script") - logger.debug(f"Found {len(css_links)} CSS links and {len(js_scripts)} JS scripts") - for css in css_links: - if css.get("href"): - css_url = css.get("href") - logger.debug(f"Downloading CSS file: {css_url}") - res = requests.get(css_url) - if res.ok: - file_name = css_url.split("/")[-1] - # Download CSS file - (new_dir / "public" / file_name).write_text(res.text) - # Rewrite CSS file to use relative paths - css["href"] = f"./{file_name}" - else: - raise Exception( - f"Failed to download CSS file: {res.status_code} {res.reason}") - for js in js_scripts: - if js.get("src"): - js_url = js.get("src") - logger.debug(f"Downloading JS file: {js_url}") - res = requests.get(js_url) - if res.ok: - file_name = js_url.split("/")[-1] - # Download JS file - (new_dir / "public" / file_name).write_text(res.text) - # Rewrite JS file to use relative paths - js["src"] = f"./{file_name}" - else: - raise Exception( - f"Failed to download JS file: {res.status_code} {res.reason}") - sim_html = soup.prettify(formatter="html5") - (new_dir / "public" / "---simulator.html").write_text(sim_html) - # Copy or download icon to favicon.ico in public directory - if config.icon: - logger.debug(f"Found icon to use") - if config.icon_source_type == IconSourceType.URL: - logger.debug(f"Downloading icon from {config.icon}") - res = requests.get(config.icon) - buffer = BytesIO(res.content) - if res.ok: - im = Image.open(buffer) - else: - raise Exception( - f"Failed to download icon: {res.status_code} {res.reason}") - else: - logger.debug(f"Reading icon from {config.icon}") - im = Image.open(config.icon) - logger.debug("Saving icon as favicon.ico") - im.save(new_dir / "public" / "favicon.ico") diff --git a/src/convert/website_to_electron/__init__.py b/src/convert/website_to_electron/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/convert/website_to_electron/electron.py b/src/convert/website_to_electron/electron.py deleted file mode 100644 index 34d4e50..0000000 --- a/src/convert/website_to_electron/electron.py +++ /dev/null @@ -1,122 +0,0 @@ -import json -import logging -import shutil -from io import BytesIO -from pathlib import Path -from typing import Callable - -import requests -from PIL import Image - -from convert.mkcd_to_website.config import Config, IconSourceType, SourceType -from utils.cmd import run_shell_command -from utils.filesystem import copy_these, delete_these -from utils.logger import create_logger - -logger = create_logger(name=__name__, level=logging.INFO) - - -def get_icon(config: Config, src_dir: Path): - """ - Prepares the icon for the Electron app. If the icon is a URL, it downloads the icon - and saves it to the specified path. If the icon is a local file, it copies the file - to the specified path. Then it will convert it to ICO for Windows, ICNS for Mac, and - PNG for Linux. - - :param config: The configuration object containing the project information. - :param src_dir: The src directory of the Electron app - the icon will be saved here. - """ - if config.icon is None: - logger.debug("No icon specified, skipping icon generation.") - return - logger.debug(f"Preparing icon") - icon_dir = src_dir / "assets" / "icons" - icon_dir.mkdir(parents=True, exist_ok=True) - if config.icon_source_type == IconSourceType.PATH: - path = Path(config.icon) - source_icon_path = icon_dir / f"source{path.suffix}" - logger.debug(f"Copying icon from {path} to {source_icon_path}") - shutil.copy(path, source_icon_path) - else: - url = config.icon - logger.debug(f"Downloading icon from {url}") - res = requests.get(url) - if not res.ok: - logger.error(f"Failed to download icon from {url}") - raise Exception(f"Failed to download icon from {url}") - buffer = BytesIO(res.content) - logger.debug( - f"Downloaded image size {round(buffer.getbuffer().nbytes / 1024)} kb") - img = Image.open(buffer) - source_icon_path = icon_dir / f"source.png" - img.save(source_icon_path) - logger.debug(f"Saved icon to {source_icon_path}") - - formats = ["ico", "icns", "png"] - source_img = Image.open(source_icon_path) - for format in formats: - icon_path = icon_dir / f"icon.{format}" - logger.debug(f"Converting icon to {format} and saving to {icon_path}") - source_img.save(icon_path, format=format.upper(), - sizes=[(256, 256)] if format == "ico" else None) - - -def generate_electron(config: Config, prj_name: str, template_dir: Path, dist_dir: Path, - cwd: Path): - """ - Generate the Electron app from static HTML, CSS, and JS files. Assumes index.html - is the entry point. - - :param config: The configuration object containing the project information. - :param prj_name: The name of the project. - :param template_dir: The directory containing the template files. - :param dist_dir: The dist directory with all the static HTML, CSS, and JS files. - :param cwd: The current working directory where the project will be created. - """ - logger.debug(f"Creating Electron app for {prj_name}") - # Initialize an Electron project - prj_dir = cwd / prj_name - prj_src_dir = prj_dir / "src" - if prj_dir.exists(): - logger.debug(f"Project {prj_name} already exists, continuing...") - else: - run_shell_command( - f"npx --yes create-electron-app@latest {prj_name} --template=webpack", - cwd=cwd) - delete_these(["package-lock.json"], prj_dir) - delete_these(["index.html", "index.css"], prj_src_dir) - # Start copying files from template - old_dir = template_dir - new_dir = prj_dir - - def copy_template(file_name: str, callback: Callable[[str], str] = lambda x: x): - (new_dir / file_name).write_text(callback((old_dir / file_name).read_text())) - - logger.debug(f"Copying website files from {old_dir} to {new_dir}") - # Modify package.json - package_json = json.loads((old_dir / "package.json").read_text()) - package_json["name"] = prj_name - package_json["productName"] = config.title - package_json["version"] = config.version - package_json["description"] = config.description - package_json["author"] = config.author - (new_dir / "package.json").write_text(json.dumps(package_json, indent=2)) - # Copy README.md - copy_template("README.md", - lambda x: x.format(WEBSITE_NAME=prj_name, - SOURCE=f"{config.source} @ {config.source_checkout}" if config.source_type == SourceType.GITHUB else config.source)) - # Copy forge.config.js, webpack.main.config.js, etc. - for file_name in ("forge.config.js", "webpack.main.config.js", - "webpack.renderer.config.js", "webpack.rules.js"): - copy_template(file_name) - # Copy src directory - copy_these(list([p.name for p in (old_dir / "src").glob("*")]), old_dir / "src", - prj_dir / "src") - # Copy dist directory - static_dir = prj_src_dir / "static" - static_dir.mkdir(parents=True, exist_ok=True) - copy_these(list([p.name for p in dist_dir.glob("*")]), dist_dir, static_dir) - # Get icons - get_icon(config, prj_src_dir) - # yarn - run_shell_command("yarn", cwd=new_dir) diff --git a/src/convert/website_to_tauri/__init__.py b/src/convert/website_to_tauri/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/convert/website_to_tauri/tauri.py b/src/convert/website_to_tauri/tauri.py deleted file mode 100644 index 78af445..0000000 --- a/src/convert/website_to_tauri/tauri.py +++ /dev/null @@ -1,127 +0,0 @@ -import json -import logging -import shutil -from io import BytesIO -from pathlib import Path -from typing import Callable - -import requests -from PIL import Image - -from convert.mkcd_to_website.config import Config, IconSourceType, SourceType -from utils.cmd import run_shell_command -from utils.filesystem import copy_these, delete_these -from utils.logger import create_logger - -logger = create_logger(name=__name__, level=logging.INFO) - - -def get_icon(config: Config, src_dir: Path): - """ - Prepares the icon for the Electron app. If the icon is a URL, it downloads the icon - and saves it to the specified path. If the icon is a local file, it copies the file - to the specified path. Then it will convert it to ICO for Windows, ICNS for Mac, and - PNG for Linux. - - :param config: The configuration object containing the project information. - :param src_dir: The src-tauri directory of the Tauri app - the icon will be saved - here. - """ - if config.icon is None: - logger.debug("No icon specified, skipping icon generation.") - return - logger.debug(f"Preparing icon") - icon_dir = src_dir / "icons" - icon_dir.mkdir(parents=True, exist_ok=True) - if config.icon_source_type == IconSourceType.PATH: - path = Path(config.icon) - source_icon_path = icon_dir / f"source{path.suffix}" - logger.debug(f"Copying icon from {path} to {source_icon_path}") - shutil.copy(path, source_icon_path) - else: - url = config.icon - logger.debug(f"Downloading icon from {url}") - res = requests.get(url) - if not res.ok: - logger.error(f"Failed to download icon from {url}") - raise Exception(f"Failed to download icon from {url}") - buffer = BytesIO(res.content) - logger.debug( - f"Downloaded image size {round(buffer.getbuffer().nbytes / 1024)} kb") - img = Image.open(buffer) - source_icon_path = icon_dir / f"source.png" - img.save(source_icon_path) - logger.debug(f"Saved icon to {source_icon_path}") - - formats = ["ico", "icns", "png"] - source_img = Image.open(source_icon_path) - for format in formats: - icon_path = icon_dir / f"icon.{format}" - logger.debug(f"Converting icon to {format} and saving to {icon_path}") - source_img.save(icon_path, format=format.upper(), - sizes=[(256, 256)] if format == "ico" else None) - - -def generate_tauri(config: Config, prj_name: str, template_dir: Path, dist_dir: Path, - cwd: Path): - """ - Generate the Tauri app from static HTML, CSS, and JS files. - - :param config: The configuration object containing the project information. - :param prj_name: The name of the project. - :param template_dir: The directory containing the template files. - :param dist_dir: The dist directory with all the static HTML, CSS, and JS files. - :param cwd: The current working directory where the project will be created. - """ - logger.debug(f"Creating Tauri app for {prj_name}") - # Initialize a Tauri project - prj_dir = cwd / prj_name - prj_src_dir = prj_dir / "src" - if prj_dir.exists(): - logger.debug(f"Project {prj_name} already exists, continuing...") - else: - run_shell_command( - f"yarn create tauri-app {prj_name} -m yarn -t vanilla -y", - cwd=cwd) - delete_these([".vscode"], prj_dir) - delete_these(["assets", "index.html", "main.js", "style.css"], prj_src_dir) - # Start copying files from template - old_dir = template_dir - new_dir = prj_dir - - def copy_template(file_name: str, callback: Callable[[str], str] = lambda x: x): - (new_dir / file_name).write_text(callback((old_dir / file_name).read_text())) - - logger.debug(f"Copying website files from {old_dir} to {new_dir}") - # Modify package.json - package_json = json.loads((old_dir / "package.json").read_text()) - package_json["name"] = prj_name - package_json["version"] = config.version - package_json["description"] = config.description - package_json["author"] = config.author - (new_dir / "package.json").write_text(json.dumps(package_json, indent=2)) - # Copy README.md - copy_template("README.md", - lambda x: x.format(WEBSITE_NAME=prj_name, - SOURCE=f"{config.source} @ {config.source_checkout}" if config.source_type == SourceType.GITHUB else config.source)) - # Copy src-tauri directory - copy_these(list([p.name for p in (old_dir / "src-tauri").glob("*")]), - old_dir / "src-tauri", - prj_dir / "src-tauri") - # Modify src-tauri/tauri.conf.json - tauri_conf_json = json.loads((old_dir / "src-tauri/tauri.conf.json").read_text()) - tauri_conf_json["productName"] = config.title - tauri_conf_json["version"] = config.version - tauri_conf_json["identifier"] = f"com.{prj_name}.app" - tauri_conf_json["app"]["windows"][0]["title"] = config.title - tauri_conf_json["app"]["windows"][0]["width"] = 160 * 4 - tauri_conf_json["app"]["windows"][0]["height"] = 120 * 4 - (new_dir / "src-tauri" / "tauri.conf.json").write_text( - json.dumps(tauri_conf_json, indent=2)) - # Copy dist directory - prj_src_dir.mkdir(parents=True, exist_ok=True) - copy_these(list([p.name for p in dist_dir.glob("*")]), dist_dir, prj_src_dir) - # Get icons - get_icon(config, prj_dir / "src-tauri") - # yarn - run_shell_command("yarn", cwd=prj_dir) diff --git a/src/main.py b/src/main.py index f623106..d3199d2 100644 --- a/src/main.py +++ b/src/main.py @@ -2,13 +2,6 @@ from argparse import ArgumentParser from pathlib import Path -from convert.mkcd_to_website.config import OutputType, parse_config -from convert.mkcd_to_website.source import download_source -from convert.mkcd_to_website.website import generate_website -from convert.website_to_electron.electron import generate_electron -from convert.website_to_tauri.tauri import generate_tauri -from utils.cmd import run_shell_command -from utils.filesystem import delete_these from utils.logger import create_logger, set_all_stdout_logger_levels logger = create_logger(name=__name__, level=logging.INFO) @@ -17,162 +10,11 @@ "standalone offline executable!") parser.add_argument("config_path", type=Path, help="Path to the YAML configuration file.") -parser.add_argument("--no-cache", action="store_true", - help="Do not use cached files. This will delete and download all " - "necessary files.") -parser.add_argument("--skip-source-download", action="store_true", - help="Skip source code download. This is useful for debugging.") -parser.add_argument("--skip-bin-build", action="store_true", - help="Skip building the game binary. This is useful for debugging.") -parser.add_argument("--skip-website-gen", action="store_true", - help="Skip website generation. This is useful for debugging.") -parser.add_argument("--skip-website-build", action="store_true", - help="Skip building the website. This is useful for debugging.") -parser.add_argument("--skip-electron-gen", action="store_true", - help="Skip Electron app generation. This is useful for debugging.") -parser.add_argument("--skip-electron-build", action="store_true", - help="Skip building the Electron app. This is useful for debugging.") -parser.add_argument("--skip-tauri-gen", action="store_true", - help="Skip Tauri app generation. This is useful for debugging.") -parser.add_argument("--skip-tauri-build", action="store_true", - help="Skip building the Tauri app. This is useful for debugging.") parser.add_argument("--debug", action="store_true", help="Enable debug logging.") + args = parser.parse_args() debug = bool(args.debug) if debug: set_all_stdout_logger_levels(logging.DEBUG) logger.debug(f"Received arguments: {args}") - -config_path = Path(args.config_path) -logger.info(f"Loading configuration from {config_path}") -config = parse_config(config_path.read_text(), config_path.parent) - -output_format = config.output -logger.debug(f"Building to {output_format.value}") -logger.debug(f"Window title will be {config.title}") - -no_cache = bool(args.no_cache) -if no_cache: - logger.info("No cache option selected. Ignoring cached files.") -skip_source_download = bool(args.skip_source_download) -skip_bin_build = bool(args.skip_bin_build) -skip_website_gen = bool(args.skip_website_gen) -skip_website_build = bool(args.skip_website_build) -skip_electron_gen = bool(args.skip_electron_gen) -skip_electron_build = bool(args.skip_electron_build) -skip_tauri_gen = bool(args.skip_tauri_gen) -skip_tauri_build = bool(args.skip_tauri_build) - -cwd = config_path.parent / config.name -src_dir = Path(__file__).parent -logger.debug(f"Current working directory: {cwd} (source code directory will be " - f"downloaded here)") -logger.debug(f"Source code directory: {src_dir}") -cwd.mkdir(parents=True, exist_ok=True) - -# Download source code -if skip_source_download: - logger.info("Skipping source code download") - source_code_path = cwd / f"{config.name} source" -else: - logger.info("Downloading source code") - source_code_path = download_source(config, cwd, no_cache) - -# npx pxt build -binary_js_path = source_code_path / "built" / "binary.js" -if skip_bin_build: - logger.info("Skipping build") -else: - logger.info("Building project") - if no_cache: - logger.debug("Checking for binary to remove") - if binary_js_path.exists(): - logger.debug(f"Deleting {binary_js_path}") - binary_js_path.unlink() - run_shell_command("npx mkc build -j", cwd=source_code_path) -logger.debug(f"Binary JS path: {binary_js_path}") - -# yarn create vite, copy files, and substitute values -vite_project_name = f"{config.name.lower().replace(" ", "-")}-website" -website_path = cwd / vite_project_name -if skip_website_gen: - logger.info("Skipping website generation") -else: - logger.info(f"Generating TS React and Vite website") - if no_cache: - logger.debug("Checking for existing website to remove") - delete_these([vite_project_name], cwd) - logger.debug(f"Creating Vite project with name {vite_project_name}") - generate_website(config, vite_project_name, src_dir / "templates" / "website_files", - cwd, binary_js_path) - -# yarn run build -website_dist_path = website_path / "dist" -if skip_website_build: - logger.info("Skipping website build") -else: - logger.info("Building website") - run_shell_command("yarn build", cwd=website_path) - -logger.info(f"Static website files are at {website_dist_path}") -if output_format == OutputType.STATIC: - logger.info(f"Build finished") - exit(0) -elif output_format == OutputType.ELECTRON: - electron_project_name = f"{config.name.lower().replace(" ", "-")}-electron" - electron_path = cwd / electron_project_name - if skip_electron_gen: - logger.info("Skipping Electron app generation") - else: - logger.info(f"Generating Electron app") - logger.debug( - f"Creating Electron app in {cwd}, using {website_dist_path} for source") - logger.debug(f"Creating Electron project with name {electron_project_name}") - # npx create-electron-app@latest, copy files, and substitute values - if no_cache: - logger.debug("Checking for existing website to remove") - delete_these([electron_project_name], cwd) - generate_electron(config, electron_project_name, - src_dir / "templates" / "electron_files", website_dist_path, - cwd) - - # yarn run make - electron_dist_path = electron_path / "out" - if skip_electron_build: - logger.info("Skipping Electron app build") - else: - logger.info("Building Electron app") - run_shell_command("yarn run make", cwd=electron_path) - - logger.info(f"Electron app executables are at {electron_dist_path}") - logger.info(f"Build finished") - exit(0) -elif output_format == OutputType.TAURI: - tauri_project_name = f"{config.name.lower().replace(' ', '-')}-tauri" - tauri_path = cwd / tauri_project_name - if skip_tauri_gen: - logger.info("Skipping Tauri app generation") - else: - logger.info(f"Generating Tauri app") - logger.debug( - f"Creating Tauri app in {cwd}, using {website_dist_path} for source") - logger.debug(f"Creating Tauri project with name {tauri_project_name}") - # yarn create tauri-app - if no_cache: - logger.debug("Checking for existing website to remove") - delete_these([tauri_project_name], cwd) - generate_tauri(config, tauri_project_name, - src_dir / "templates" / "tauri_files", website_dist_path, cwd) - - # yarn run tauri build - tauri_dist_path = tauri_path / "src-tauri" / "target" / "release" - if skip_tauri_build: - logger.info("Skipping Tauri app build") - else: - logger.info("Building Tauri app") - run_shell_command("yarn run tauri build", cwd=tauri_path) - - logger.info(f"Tauri app executables are at {tauri_dist_path}") - logger.info(f"Build finished") - exit(0) diff --git a/src/templates/electron_files/README.md b/src/templates/electron_files/README.md deleted file mode 100644 index 5eccfb2..0000000 --- a/src/templates/electron_files/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# {WEBSITE_NAME} - -Electron app of a React TS Vite website static export bundle of {SOURCE}. - -Generated by -[MakeCode-Arcade-to-App](https://github.com/UnsignedArduino/MakeCode-Arcade-to-App). diff --git a/src/templates/electron_files/forge.config.js b/src/templates/electron_files/forge.config.js deleted file mode 100644 index 57b68f1..0000000 --- a/src/templates/electron_files/forge.config.js +++ /dev/null @@ -1,65 +0,0 @@ -const {FusesPlugin} = require('@electron-forge/plugin-fuses'); -const {FuseV1Options, FuseVersion} = require('@electron/fuses'); - -module.exports = { - packagerConfig: { - asar: true, - extraResource: ["./src/static/binary.js"], - icon: "./src/assets/icons/icon" - }, - rebuildConfig: {}, - makers: [ - { - name: '@electron-forge/maker-squirrel', - config: {}, - }, - { - name: '@electron-forge/maker-zip', - platforms: ['darwin'], - }, - { - name: '@electron-forge/maker-deb', - config: {}, - }, - { - name: '@electron-forge/maker-rpm', - config: {}, - }, - ], - plugins: [ - { - name: '@electron-forge/plugin-auto-unpack-natives', - config: {}, - }, - { - name: '@electron-forge/plugin-webpack', - config: { - mainConfig: './webpack.main.config.js', - renderer: { - config: './webpack.renderer.config.js', - entryPoints: [ - { - html: './src/static/index.html', - js: './src/renderer.js', - name: 'main_window', - preload: { - js: './src/preload.js', - }, - }, - ], - }, - }, - }, - // Fuses are used to enable/disable various Electron functionality - // at package time, before code signing the application - new FusesPlugin({ - version: FuseVersion.V1, - [FuseV1Options.RunAsNode]: false, - [FuseV1Options.EnableCookieEncryption]: true, - [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false, - [FuseV1Options.EnableNodeCliInspectArguments]: false, - [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true, - [FuseV1Options.OnlyLoadAppFromAsar]: true, - }), - ], -}; diff --git a/src/templates/electron_files/package.json b/src/templates/electron_files/package.json deleted file mode 100644 index eada747..0000000 --- a/src/templates/electron_files/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "NAME", - "productName": "NAME", - "author": "AUTHOR", - "version": "VERSION", - "description": "DESCRIPTION", - "main": ".webpack/main", - "scripts": { - "start": "electron-forge start", - "package": "electron-forge package", - "make": "electron-forge make", - "publish": "electron-forge publish", - "lint": "echo \"No linting configured\"" - }, - "keywords": [], - "devDependencies": { - "@electron-forge/cli": "^7.8.1", - "@electron-forge/maker-deb": "^7.8.1", - "@electron-forge/maker-rpm": "^7.8.1", - "@electron-forge/maker-squirrel": "^7.8.1", - "@electron-forge/maker-zip": "^7.8.1", - "@electron-forge/plugin-auto-unpack-natives": "^7.8.1", - "@electron-forge/plugin-fuses": "^7.8.1", - "@electron-forge/plugin-webpack": "^7.8.1", - "@electron/fuses": "^1.8.0", - "@vercel/webpack-asset-relocator-loader": "1.7.3", - "css-loader": "^6.11.0", - "electron": "36.2.0", - "copy-webpack-plugin": "^13.0.0", - "node-loader": "^2.1.0", - "style-loader": "^3.3.4" - }, - "dependencies": { - "electron-squirrel-startup": "^1.0.1" - } -} diff --git a/src/templates/electron_files/src/main.js b/src/templates/electron_files/src/main.js deleted file mode 100644 index 95f70e8..0000000 --- a/src/templates/electron_files/src/main.js +++ /dev/null @@ -1,73 +0,0 @@ -const {app, BrowserWindow, protocol, net} = require("electron") -const path = require("node:path") -const fs = require("node:fs") -const url = require("node:url") - -// Handle creating/removing shortcuts on Windows when installing/uninstalling. -if (require('electron-squirrel-startup')) { - app.quit(); -} - -const windowScale = 4; - -const createWindow = () => { - // Create the browser window. - const mainWindow = new BrowserWindow({ - width: 160 * windowScale, - height: 127 * windowScale, - autoHideMenuBar: true, - webPreferences: { - preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY, - }, - icon: "./src/assets/icons/icon.png", - }); - - // and load the index.html of the app. - mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY); - - // Open the DevTools. - // mainWindow.webContents.openDevTools(); -}; - -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. -app.whenReady().then(() => { - createWindow(); - - // On OS X it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); - } - }); - - console.log("Will intercept file requests for binary.js"); - console.log(`process.resourcesPath: ${process.resourcesPath}`); - protocol.handle('file', (rq) => { - const u = new URL(rq.url); - const filePath = u.pathname; - if (filePath.endsWith("binary.js")) { - const newPath = path.join(process.resourcesPath, "binary.js"); - const newURL = url.pathToFileURL(newPath); - console.log(`Requested for ${filePath}, serving ${newURL} instead`); - return net.fetch(newURL.toString(), {bypassCustomProtocolHandlers: true}); - } else { - console.log(`Requested for ${filePath}`); - return net.fetch(rq, {bypassCustomProtocolHandlers: true}); - } - }); -}); - -// Quit when all windows are closed, except on macOS. There, it's common -// for applications and their menu bar to stay active until the user quits -// explicitly with Cmd + Q. -app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit(); - } -}); - -// In this file you can include the rest of your app's specific main process -// code. You can also put them in separate files and import them here. diff --git a/src/templates/electron_files/src/preload.js b/src/templates/electron_files/src/preload.js deleted file mode 100644 index 5e9d369..0000000 --- a/src/templates/electron_files/src/preload.js +++ /dev/null @@ -1,2 +0,0 @@ -// See the Electron documentation for details on how to use preload scripts: -// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts diff --git a/src/templates/electron_files/src/renderer.js b/src/templates/electron_files/src/renderer.js deleted file mode 100644 index d8ef8f1..0000000 --- a/src/templates/electron_files/src/renderer.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * This file will automatically be loaded by webpack and run in the "renderer" context. - * To learn more about the differences between the "main" and the "renderer" context in - * Electron, visit: - * - * https://electronjs.org/docs/tutorial/process-model - * - * By default, Node.js integration in this file is disabled. When enabling Node.js integration - * in a renderer process, please be aware of potential security implications. You can read - * more about security risks here: - * - * https://electronjs.org/docs/tutorial/security - * - * To enable Node.js integration in this file, open up `main.js` and enable the `nodeIntegration` - * flag: - * - * ``` - * // Create the browser window. - * mainWindow = new BrowserWindow({ - * width: 800, - * height: 600, - * webPreferences: { - * nodeIntegration: true - * } - * }); - * ``` - */ - -console.log('👋 This message is being logged by "renderer.js", included via webpack'); diff --git a/src/templates/electron_files/webpack.main.config.js b/src/templates/electron_files/webpack.main.config.js deleted file mode 100644 index 3db351b..0000000 --- a/src/templates/electron_files/webpack.main.config.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - /** - * This is the main entry point for your application, it's the first file - * that runs in the main process. - */ - entry: './src/main.js', - // Put your normal webpack config below here - module: { - rules: require('./webpack.rules'), - } -}; diff --git a/src/templates/electron_files/webpack.renderer.config.js b/src/templates/electron_files/webpack.renderer.config.js deleted file mode 100644 index 4d8c816..0000000 --- a/src/templates/electron_files/webpack.renderer.config.js +++ /dev/null @@ -1,27 +0,0 @@ -const rules = require('./webpack.rules'); -const CopyWebpackPlugin = require('copy-webpack-plugin'); - -rules.push(...[ - {test: /\.css$/, use: [{loader: 'style-loader'}, {loader: 'css-loader'}]} -]); - -module.exports = { - // Put your normal webpack config below here - module: { - rules - }, - plugins: [ - new CopyWebpackPlugin({ - patterns: [ - { - from: "./src/static", - to: "./main_window", - globOptions: { - ignore: ["**/index.html"] - } - } - ], - - }) - ] -}; diff --git a/src/templates/electron_files/webpack.rules.js b/src/templates/electron_files/webpack.rules.js deleted file mode 100644 index 23cb22a..0000000 --- a/src/templates/electron_files/webpack.rules.js +++ /dev/null @@ -1,35 +0,0 @@ -module.exports = [ - // Add support for native node modules - { - // We're specifying native_modules in the test because the asset relocator loader generates a - // "fake" .node file which is really a cjs file. - test: /native_modules[/\\].+\.node$/, - use: 'node-loader', - }, - { - test: /[/\\]node_modules[/\\].+\.(m?js|node)$/, - parser: { amd: false }, - use: { - loader: '@vercel/webpack-asset-relocator-loader', - options: { - outputAssetBase: 'native_modules', - }, - }, - }, - // Put your webpack loader rules in this array. This is where you would put - // your ts-loader configuration for instance: - /** - * Typescript Example: - * - * { - * test: /\.tsx?$/, - * exclude: /(node_modules|.webpack)/, - * loaders: [{ - * loader: 'ts-loader', - * options: { - * transpileOnly: true - * } - * }] - * } - */ -]; diff --git a/src/templates/tauri_files/.gitignore b/src/templates/tauri_files/.gitignore deleted file mode 100644 index a547bf3..0000000 --- a/src/templates/tauri_files/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/src/templates/tauri_files/README.md b/src/templates/tauri_files/README.md deleted file mode 100644 index 92d2f29..0000000 --- a/src/templates/tauri_files/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# {WEBSITE_NAME} - -Tauri app of a React TS Vite website static export bundle of {SOURCE}. - -Generated by -[MakeCode-Arcade-to-App](https://github.com/UnsignedArduino/MakeCode-Arcade-to-App). diff --git a/src/templates/tauri_files/package.json b/src/templates/tauri_files/package.json deleted file mode 100644 index 3d2d099..0000000 --- a/src/templates/tauri_files/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "tauri-app", - "private": true, - "version": "0.1.0", - "type": "module", - "scripts": { - "tauri": "tauri" - }, - "devDependencies": { - "@tauri-apps/cli": "^2" - } -} diff --git a/src/templates/tauri_files/src-tauri/.gitignore b/src/templates/tauri_files/src-tauri/.gitignore deleted file mode 100644 index b21bd68..0000000 --- a/src/templates/tauri_files/src-tauri/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -/target/ - -# Generated by Tauri -# will have schema files for capabilities auto-completion -/gen/schemas diff --git a/src/templates/tauri_files/src-tauri/Cargo.toml b/src/templates/tauri_files/src-tauri/Cargo.toml deleted file mode 100644 index 6875383..0000000 --- a/src/templates/tauri_files/src-tauri/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "tauri-app" -version = "0.1.0" -description = "A Tauri App" -authors = ["you"] -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -# The `_lib` suffix may seem redundant but it is necessary -# to make the lib name unique and wouldn't conflict with the bin name. -# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 -name = "tauri_app_lib" -crate-type = ["staticlib", "cdylib", "rlib"] - -[build-dependencies] -tauri-build = { version = "2", features = [] } - -[dependencies] -tauri = { version = "2", features = [] } -tauri-plugin-opener = "2" -serde = { version = "1", features = ["derive"] } -serde_json = "1" - diff --git a/src/templates/tauri_files/src-tauri/build.rs b/src/templates/tauri_files/src-tauri/build.rs deleted file mode 100644 index d860e1e..0000000 --- a/src/templates/tauri_files/src-tauri/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - tauri_build::build() -} diff --git a/src/templates/tauri_files/src-tauri/capabilities/default.json b/src/templates/tauri_files/src-tauri/capabilities/default.json deleted file mode 100644 index 4cdbf49..0000000 --- a/src/templates/tauri_files/src-tauri/capabilities/default.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "../gen/schemas/desktop-schema.json", - "identifier": "default", - "description": "Capability for the main window", - "windows": ["main"], - "permissions": [ - "core:default", - "opener:default" - ] -} diff --git a/src/templates/tauri_files/src-tauri/icons/.keep b/src/templates/tauri_files/src-tauri/icons/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/templates/tauri_files/src-tauri/src/lib.rs b/src/templates/tauri_files/src-tauri/src/lib.rs deleted file mode 100644 index 4a277ef..0000000 --- a/src/templates/tauri_files/src-tauri/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ -#[tauri::command] -fn greet(name: &str) -> String { - format!("Hello, {}! You've been greeted from Rust!", name) -} - -#[cfg_attr(mobile, tauri::mobile_entry_point)] -pub fn run() { - tauri::Builder::default() - .plugin(tauri_plugin_opener::init()) - .invoke_handler(tauri::generate_handler![greet]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} diff --git a/src/templates/tauri_files/src-tauri/src/main.rs b/src/templates/tauri_files/src-tauri/src/main.rs deleted file mode 100644 index 2abccd9..0000000 --- a/src/templates/tauri_files/src-tauri/src/main.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Prevents additional console window on Windows in release, DO NOT REMOVE!! -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -fn main() { - tauri_app_lib::run() -} diff --git a/src/templates/tauri_files/src-tauri/tauri.conf.json b/src/templates/tauri_files/src-tauri/tauri.conf.json deleted file mode 100644 index 3d78041..0000000 --- a/src/templates/tauri_files/src-tauri/tauri.conf.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "$schema": "https://schema.tauri.app/config/2", - "productName": "tauri-app", - "version": "0.1.0", - "identifier": "com.tauri-app.app", - "build": { - "frontendDist": "../src" - }, - "app": { - "withGlobalTauri": true, - "windows": [ - { - "title": "tauri-app", - "width": 800, - "height": 600 - } - ], - "security": { - "csp": null - } - }, - "bundle": { - "active": true, - "targets": "all", - "icon": [ - "icons/icon.png", - "icons/icon.icns", - "icons/icon.ico" - ] - } -} diff --git a/src/templates/website_files/.prettierignore b/src/templates/website_files/.prettierignore deleted file mode 100644 index a48cf0d..0000000 --- a/src/templates/website_files/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -public diff --git a/src/templates/website_files/README.md b/src/templates/website_files/README.md deleted file mode 100644 index 4875af7..0000000 --- a/src/templates/website_files/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# {WEBSITE_NAME} - -Bundle of {SOURCE} to a React TS Vite website. - -Generated by -[MakeCode-Arcade-to-App](https://github.com/UnsignedArduino/MakeCode-Arcade-to-App). diff --git a/src/templates/website_files/eslint.config.js b/src/templates/website_files/eslint.config.js deleted file mode 100644 index 920e044..0000000 --- a/src/templates/website_files/eslint.config.js +++ /dev/null @@ -1,43 +0,0 @@ -import js from "@eslint/js"; -import globals from "globals"; -import reactHooks from "eslint-plugin-react-hooks"; -import reactRefresh from "eslint-plugin-react-refresh"; -import reactX from "eslint-plugin-react-x"; -import reactDom from "eslint-plugin-react-dom"; -import tseslint from "typescript-eslint"; - -export default tseslint.config( - { ignores: ["dist", "public"] }, - { - extends: [ - js.configs.recommended, - ...tseslint.configs.recommendedTypeChecked, - // ...tseslint.configs.strictTypeChecked, - ...tseslint.configs.stylisticTypeChecked, - ], - files: ["**/*.{ts,tsx}"], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - parserOptions: { - project: ["./tsconfig.node.json", "./tsconfig.app.json"], - tsconfigRootDir: import.meta.dirname, - }, - }, - plugins: { - "react-hooks": reactHooks, - "react-refresh": reactRefresh, - "react-x": reactX, - "react-dom": reactDom, - }, - rules: { - ...reactHooks.configs.recommended.rules, - "react-refresh/only-export-components": [ - "warn", - { allowConstantExport: true }, - ], - ...reactX.configs["recommended-typescript"].rules, - ...reactDom.configs.recommended.rules, - }, - }, -); diff --git a/src/templates/website_files/index.html b/src/templates/website_files/index.html deleted file mode 100644 index 31a5cf5..0000000 --- a/src/templates/website_files/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - {TITLE} - - - -
- - - diff --git a/src/templates/website_files/package.json b/src/templates/website_files/package.json deleted file mode 100644 index 1bd8280..0000000 --- a/src/templates/website_files/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "NAME", - "description": "DESCRIPTION", - "author": "AUTHOR", - "private": true, - "version": "VERSION", - "type": "module", - "scripts": { - "dev": "vite", - "lint": "eslint .", - "writeLint": "eslint --fix .", - "format": "prettier --check .", - "writeFormat": "prettier --write .", - "build": "tsc -b && vite build", - "preview": "vite preview" - }, - "dependencies": { - "react": "^19.0.0", - "react-dom": "^19.0.0", - "react-toastify": "^11.0.5" - }, - "devDependencies": { - "@eslint/js": "^9.21.0", - "@types/react": "^19.0.10", - "@types/react-dom": "^19.0.4", - "@vitejs/plugin-react": "^4.3.4", - "eslint": "^9.21.0", - "eslint-plugin-react-dom": "^1.42.1", - "eslint-plugin-react-hooks": "^5.1.0", - "eslint-plugin-react-refresh": "^0.4.19", - "eslint-plugin-react-x": "^1.42.1", - "globals": "^15.15.0", - "prettier": "^3.5.3", - "typescript": "~5.8.3", - "typescript-eslint": "^8.24.1", - "vite": "^6.2.0" - }, - "packageManager": "yarn@1.22.19+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447" -} diff --git a/src/templates/website_files/src/App.css b/src/templates/website_files/src/App.css deleted file mode 100644 index 6d6748a..0000000 --- a/src/templates/website_files/src/App.css +++ /dev/null @@ -1,14 +0,0 @@ -body { - background: black; - overflow: hidden; - margin: 0 -} - -iframe { - width: 100%; - height: auto; - max-width: 100vw; - max-height: 100vh; - aspect-ratio: 4 / 3; - border: none; -} diff --git a/src/templates/website_files/src/App.tsx b/src/templates/website_files/src/App.tsx deleted file mode 100644 index 486b744..0000000 --- a/src/templates/website_files/src/App.tsx +++ /dev/null @@ -1,322 +0,0 @@ -import "./App.css"; -import * as React from "react"; -import { - createEmptyLoadingToastCallbacks, - loadingToast, - type LoadingToastCallbacks, -} from "./utils/toasts.ts"; -import {toast} from "react-toastify"; -import {GameConfiguration} from "./gameConfiguration.ts"; -import {positionFixedElement} from "./utils/position.ts"; - -function App(): React.ReactNode { - const simulatorRef = React.useRef(null); - const statsRef = React.useRef(null); - const [code, setCode] = React.useState(""); - const [simState, setSimState] = React.useState({}); - - const loadingGameToastCallbacksRef = React.useRef( - createEmptyLoadingToastCallbacks(), - ); - const restartGameToastCallbacksRef = React.useRef( - createEmptyLoadingToastCallbacks(), - ); - const gameCrashToastCloseCallbackRef = React.useRef<() => void>(() => { - }); - const [showNoFocusMessage, setShowNoFocusMessage] = React.useState(false); - const [statsInnerText, setStatsInnerText] = React.useState(""); - - React.useEffect(() => { - try { - setSimState(JSON.parse(localStorage.getItem("simState") ?? "{}")); - } catch (err) { - console.warn( - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `Failed to load sim state, maybe first time run or simState is empty?\n${err}`, - ); - setSimState({}); - } - }, []); - - React.useEffect(() => { - localStorage.setItem("simState", JSON.stringify(simState)); - }, [simState]); - - React.useEffect(() => { - loadingGameToastCallbacksRef.current = GameConfiguration.Toasts - .ENABLE_LOADING_GAME_TOAST - ? loadingToast( - GameConfiguration.Toasts.LOADING_GAME_TOAST_PENDING_MSG, - GameConfiguration.Toasts.LOADING_GAME_TOAST_SUCCESS_MSG, - GameConfiguration.Toasts.LOADING_GAME_TOAST_ERROR_MSG, - ) - : createEmptyLoadingToastCallbacks(); - fetch("binary.js") - .then((res) => { - if (res.ok) { - return res.text(); - } else { - console.error(`Failed to load binary.js: ${res.statusText}`); - } - }) - .then((text) => { - if (text) { - console.log( - `Loaded ${Math.round(text.length / 1024)} kb of binary.js`, - ); - setCode(text); - if (simulatorRef.current) { - simulatorRef.current.src = - "---simulator.html?hideSimButtons=1&noExtraPadding=1&fullscreen=1&autofocus=1&nofooter=1"; - } else { - console.error("Simulator iframe ref is null"); - } - } else { - throw new Error("Failed to load binary.js: text is empty/undefined"); - } - }) - .catch((err: unknown) => { - console.error(err); - loadingGameToastCallbacksRef.current.error(); - }); - }, []); - - React.useEffect(() => { - function startSim() { - console.log("Starting simulator"); - simulatorRef.current?.contentWindow?.postMessage({ - type: "run", - parts: [], - code, - partDefinitions: [], - // cdnUrl: "https://cdn.makecode.com", - // version: "", - storedState: simState, - frameCounter: 1, - options: { - theme: "green", - player: "", - }, - id: `green-${Math.random()}`, - }); - } - - function stopSim() { - console.log("Stopping simulator"); - simulatorRef.current?.contentWindow?.postMessage({type: "stop"}); - } - - /* eslint-disable */ - function onMessageHandler(event: MessageEvent) { - const data: any = event.data; - // if (data.type !== "messagepacket") { - // alert(JSON.stringify(data)); - // } - // console.log(data); - if (data.type == "ready") { - console.log("Simulator is ready"); - startSim(); - loadingGameToastCallbacksRef.current.success(); - } else if (data.type == "simulator") { - switch (data.command) { - case "restart": { - console.log("Simulator requested restart"); - restartGameToastCallbacksRef.current = GameConfiguration.Toasts - .ENABLE_RESTARTING_GAME_TOAST - ? loadingToast( - GameConfiguration.Toasts.RESTARTING_GAME_TOAST_PENDING_MSG, - GameConfiguration.Toasts.RESTARTING_GAME_TOAST_SUCCESS_MSG, - GameConfiguration.Toasts.RESTARTING_GAME_TOAST_ERROR_MSG, - ) - : createEmptyLoadingToastCallbacks(); - stopSim(); - gameCrashToastCloseCallbackRef.current(); - setTimeout(() => { - startSim(); - restartGameToastCallbacksRef.current.success(); - }, 500); - break; - } - case "setstate": { - if (data.stateValue === null) { - setSimState({ - // @ts-ignore - ...simState, - [data.stateKey]: undefined, - }); - } else { - setSimState({ - // @ts-ignore - ...simState, - [data.stateKey]: data.stateValue, - }); - } - break; - } - default: - break; - } - } else if (data.type == "debugger" && data.subtype == "breakpoint") { - // Error most likely - console.error("Simulator may have crashed!"); - console.error(data); - if (GameConfiguration.Toasts.ENABLE_POSSIBLE_GAME_CRASH_TOAST) { - toast.error( - ({closeToast}) => { - gameCrashToastCloseCallbackRef.current = closeToast; - return ( -
- { - GameConfiguration.Toasts - .POSSIBLE_GAME_CRASH_TOAST_BEGINNING_MSG - } - - {GameConfiguration.Toasts.POSSIBLE_GAME_CRASH_TOAST_END_MSG} -
- ); - }, - { - autoClose: - GameConfiguration.Toasts.POSSIBLE_GAME_CRASH_TOAST_AUTOCLOSE, - closeOnClick: - GameConfiguration.Toasts - .POSSIBLE_GAME_CRASH_TOAST_CLOSE_ON_CLICK, - }, - ); - } - } - } - - /* eslint-enable */ - - window.addEventListener("message", onMessageHandler, false); - return () => { - window.removeEventListener("message", onMessageHandler, false); - }; - }, [code, simState]); - - React.useEffect(() => { - const checkStatsId = setInterval(() => { - const statsText = - simulatorRef.current?.contentDocument?.getElementById( - "debug-stats", - )?.innerText; - if (statsRef.current) { - positionFixedElement( - statsRef.current, - GameConfiguration.DebugStats.STATS_LOCATION, - ); - setStatsInnerText(statsText ?? "") - statsRef.current.innerText = statsText ?? ""; - } - }, 100); - - return () => { - clearInterval(checkStatsId); - }; - }, []); - - React.useEffect(() => { - if (!GameConfiguration.FocusDetector.ENABLE_FOCUS_DETECTOR) { - return; - } - - const checkFocusID = setInterval(() => { - setShowNoFocusMessage( - !document.hasFocus() || - !simulatorRef.current?.contentDocument?.hasFocus(), - ); - }, 100); - - return () => { - clearInterval(checkFocusID); - }; - }); - - return ( -
-