Skip to content
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .dockerignore

This file was deleted.

25 changes: 0 additions & 25 deletions Dockerfile

This file was deleted.

58 changes: 19 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,51 +37,31 @@ It does not include the necessary security measures. This tool is intended solel

---

## Installation
## Serving the Tool

### 1. Docker (Recommended)
Any static server works; the examples below cover the most common options:

This is the easiest way to run the application without installing PHP or Apache locally.
- **Node.js (http-server)**
```bash
npm install --global http-server # once
http-server -p 8080 # from the project root
```
Navigate to `http://127.0.0.1:8080/`.

1. Make sure **Docker Desktop** is installed and running.
2. Clone or download this repository.
3. Navigate to the project root in a terminal.
4. Build and start the container:
- **PHP built-in web server**
```bash
php -S 127.0.0.1:8080
```

```bash
docker-compose up --build
```
- **Python 3 (http.server)**
```bash
python3 -m http.server 8080
```

5. Open your browser and visit:
- **Any other static server**
Point Apache, Nginx, Caddy, etc. at the repository root; no rewrite rules are required.

```
http://localhost:8000/
```

> You can change the port mapping in `docker-compose.yml` if needed.

---

### 2. Direct Installation on Apache

If you prefer to run the application directly on a local Apache server:

1. Make sure you have **PHP 8+** and Apache installed.
2. Copy the project files to your Apache document root (e.g., `htdocs` or `www`).
3. Ensure the `path-to-project/` folder is accessible via your browser.
4. Adjust PHP settings if needed for large file uploads:

```ini
upload_max_filesize = 50M
post_max_size = 50M
memory_limit = 128M
```

5. Open your browser and visit:

```
http://localhost/path-to-project/index.php
```
> **Tip:** When you change code, do a hard refresh (`Ctrl`/`Cmd` + `Shift` + `R`) so the updated service worker and assets reload.

---

Expand Down
6 changes: 0 additions & 6 deletions custom-php.ini

This file was deleted.

140 changes: 140 additions & 0 deletions designer/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex">
<title>Style Designer</title>
<link rel="icon" href="../files/favicon.ico">
<link rel="stylesheet" href="../files/css/bootstrap.min.css">
<link rel="stylesheet" href="../files/css/style-designer.css">
<script defer src="../files/js/bootstrap.bundle.min.js"></script>
<script defer src="../files/js/style-storage.js"></script>
<script>
window.styleDesignerConfig = {
defaultEntry: localStorage.getItem('style-designer-default-entry') || 'index.html'
};
</script>
<script defer src="../files/js/viewer.js"></script>
</head>
<body class="designer-page">
<header id="sdHeader">
<div class="nav-group btn-group btn-group-sm" role="group" aria-label="Main navigation">
<a class="btn btn-outline-light" href="../upload/index.html">Upload</a>
<a class="btn btn-outline-light active" aria-current="page" href="./index.html">Designer</a>
<a class="btn btn-outline-light" href="../download/index.html">Download</a>
</div>
<div class="view-group btn-group btn-group-sm" id="viewSelector" role="group" aria-label="Content view" hidden>
<button type="button" class="btn btn-light" data-view="web">Website</button>
<button type="button" class="btn btn-light" data-view="page">Single page</button>
<button type="button" class="btn btn-light" data-view="scorm">SCORM 1.2</button>
</div>
<div class="config-group btn-group btn-group-sm">
<button type="button" class="btn btn-light" id="configTab" aria-pressed="false">Theme configuration</button>
<button type="button" class="btn btn-light" id="cssTab" aria-pressed="false" disabled>CSS editor</button>
</div>
<div class="action-group">
<button type="button" class="btn btn-outline-light btn-sm" id="openNewWindow" title="Open in new window" disabled>
<img src="../files/img/new-window.svg" width="24" height="24" alt="New window"><span class="visually-hidden">New window</span>
</button>
</div>
</header>
<main class="container-fluid py-3 designer-main">
<div id="previewPanel">
<div class="preview-workspace" id="previewWorkspace">
<iframe id="viewer" title="Content preview" hidden></iframe>
<section class="card shadow-sm d-none css-editor" id="cssPanel">
<div class="card-body d-flex flex-column">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="h5 mb-0">CSS Editor</h2>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-secondary" id="reloadCss">Reload</button>
<button type="button" class="btn btn-outline-secondary" id="downloadCss">Download</button>
</div>
</div>
<div id="cssMessages" aria-live="polite"></div>
<form id="cssForm" class="d-flex flex-column flex-grow-1">
<div class="mb-2 flex-grow-1">
<label for="cssEditor" class="form-label visually-hidden">CSS</label>
<div class="code-editor" id="cssEditorWrapper">
<pre class="code-editor__highlight" id="cssHighlight" aria-hidden="true"></pre>
<textarea class="code-editor__input font-monospace" id="cssEditor" name="css" rows="20" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
</div>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary btn-sm" id="saveCss">Apply to preview</button>
</div>
</form>
</div>
</section>
</div>
<div class="container p-4" id="emptyState" hidden>
<h1 class="visually-hidden">Style Designer</h1>
<div class="alert alert-info">
No contents available…
</div>
<p>Upload the exported packages in the <strong>Upload</strong> page and come back to preview them here.</p>
</div>
</div>
<section class="card shadow-sm d-none" id="configPanel">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="h5 mb-0">Theme Configuration</h2>
<button type="button" class="btn btn-sm btn-outline-secondary" id="resetConfig">Reset</button>
</div>
<div id="configMessages" aria-live="polite"></div>
<form id="configForm" novalidate>
<div class="mb-2">
<label for="configName" class="form-label">Name <span class="text-danger">*</span></label>
<input type="text" class="form-control form-control-sm" id="configName" name="name" required pattern="^[A-Za-z0-9_\-]+$" maxlength="60">
<div class="invalid-feedback">Use only letters, numbers, hyphens or underscores.</div>
<div class="form-text">Only letters, numbers, hyphens and underscores.</div>
</div>
<div class="mb-2">
<label for="configTitle" class="form-label">Title <span class="text-danger">*</span></label>
<input type="text" class="form-control form-control-sm" id="configTitle" name="title" required maxlength="120">
<div class="invalid-feedback">Title is required.</div>
</div>
<div class="row g-2">
<div class="col-sm-6">
<label for="configVersion" class="form-label">Version</label>
<input type="text" class="form-control form-control-sm" id="configVersion" name="version" maxlength="20">
</div>
<div class="col-sm-6">
<label for="configCompatibility" class="form-label">Compatibility</label>
<input type="text" class="form-control form-control-sm" id="configCompatibility" name="compatibility" maxlength="20">
</div>
</div>
<div class="mb-2 mt-2">
<label for="configAuthor" class="form-label">Author</label>
<input type="text" class="form-control form-control-sm" id="configAuthor" name="author" maxlength="120">
</div>
<div class="mb-2">
<label for="configLicense" class="form-label">License</label>
<input type="text" class="form-control form-control-sm" id="configLicense" name="license" maxlength="120">
</div>
<div class="mb-2">
<label for="configLicenseUrl" class="form-label">License URL</label>
<input type="text" class="form-control form-control-sm" id="configLicenseUrl" name="license-url" maxlength="200">
</div>
<div class="mb-2">
<label for="configDescription" class="form-label">Description</label>
<textarea class="form-control form-control-sm" id="configDescription" name="description" rows="6" maxlength="1000"></textarea>
</div>
<div class="mb-3">
<label for="configDownloadable" class="form-label">Downloadable</label>
<select class="form-select form-select-sm" id="configDownloadable" name="downloadable">
<option value="0">0 - Not downloadable</option>
<option value="1">1 - Downloadable</option>
</select>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary btn-sm">Save config.xml</button>
<button type="button" class="btn btn-outline-secondary btn-sm" id="downloadConfig">Download XML</button>
</div>
</form>
</div>
</section>
</main>
</body>
</html>
8 changes: 0 additions & 8 deletions docker-compose.yml

This file was deleted.

57 changes: 57 additions & 0 deletions download/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex">
<title>Download | Style Designer</title>
<link rel="icon" href="../files/favicon.ico">
<link rel="stylesheet" href="../files/css/bootstrap.min.css">
<link rel="stylesheet" href="../files/css/style-designer.css">
<script defer src="../files/js/bootstrap.bundle.min.js"></script>
<script defer src="../files/js/style-storage.js"></script>
<script defer src="../files/js/jszip.min.js"></script>
<script defer src="../files/js/downloader.js"></script>
</head>
<body class="upload">
<header id="sdHeader">
<div class="nav-group btn-group btn-group-sm" role="group" aria-label="Main navigation">
<a class="btn btn-outline-light" href="../upload/index.html">Upload</a>
<a class="btn btn-outline-light" href="../designer/index.html">Designer</a>
<a class="btn btn-outline-light active" aria-current="page" href="./index.html">Download</a>
</div>
</header>
<div class="container p-4">
<h1 class="h5 mb-4 visually-hidden">Download style</h1>
<div id="downloadMessages" aria-live="polite"></div>
<ol class="mt-4 mb-4 text-muted">
<li>Edit the <strong>config.xml</strong> file before downloading the style.</li>
<li>Remember that "name" is an ID and cannot contain spaces or special characters.</li>
<li>If your work is based on another style, you must respect the license terms.</li>
<li>You can add any additional information about licenses, authorship, or anything else you need in the "description" field.</li>
<li>When you're finished, click "Download Style".</li>
</ol>
<form id="downloadForm">
<button type="button" class="btn btn-primary me-1" id="downloadButton">Download Style</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal">Delete all files and create a new Style</button>
</form>
</div>
<div class="modal fade" id="confirmModal" tabindex="-1" aria-labelledby="confirmModalLabel" aria-hidden="true" data-bs-focus="false">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="h5 modal-title" id="confirmModalLabel">Are you sure?</h2>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>If you click "Continue", <strong>all files will be permanently deleted</strong>, including the uploaded content and the Style you’ve been working on. <strong>This action cannot be undone.</strong></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="confirmDeleteAction">Continue</button>
</div>
</div>
</div>
</div>
</body>
</html>
Loading