@workadventure/map-starter-kit-core 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +165 -0
  2. package/dist/assets/views/index.html +168 -0
  3. package/dist/assets/views/step1-git.html +154 -0
  4. package/dist/assets/views/step2-hosting.html +153 -0
  5. package/dist/assets/views/step3-steps-selfhosted.html +502 -0
  6. package/dist/assets/views/step3-steps.html +549 -0
  7. package/dist/assets/views/step4-validated-selfhosted.html +188 -0
  8. package/dist/assets/views/step4-validated.html +80 -0
  9. package/dist/images/world-select.png +0 -0
  10. package/dist/server.js +4 -4
  11. package/dist/server.js.map +1 -1
  12. package/dist/styles/styles.css +1 -8
  13. package/package.json +3 -1
  14. package/public/assets/js/index.js +80 -0
  15. package/public/assets/views/index.html +168 -0
  16. package/public/assets/views/step1-git.html +154 -0
  17. package/public/assets/views/step2-hosting.html +153 -0
  18. package/public/assets/views/step3-steps-selfhosted.html +502 -0
  19. package/public/assets/views/step3-steps.html +549 -0
  20. package/public/assets/views/step4-validated-selfhosted.html +188 -0
  21. package/public/assets/views/step4-validated.html +80 -0
  22. package/public/images/badumtss.svg +12 -0
  23. package/public/images/brand-discord.svg +22 -0
  24. package/public/images/brand-github.svg +19 -0
  25. package/public/images/brand-linkedin.svg +23 -0
  26. package/public/images/brand-x.svg +20 -0
  27. package/public/images/brand-youtube.svg +20 -0
  28. package/public/images/favicon.svg +50 -0
  29. package/public/images/logo.svg +72 -0
  30. package/public/images/world-select.png +0 -0
  31. package/public/styles/styles.css +424 -0
  32. package/public/styles/styles.css.map +1 -0
  33. package/types/server.d.ts +5 -0
  34. /package/dist/assets/{index.js → js/index.js} +0 -0
  35. /package/{dist/images/unknown-room-image copy.png → public/images/unknown-room-image.png} +0 -0
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # @workadventure/map-starter-kit-core
2
+
3
+ Core app, HTML pages and static assets for the **WorkAdventure Map Starter Kit**. Update this package to get new UI and server features without touching your maps or config.
4
+
5
+ ## Features
6
+
7
+ - **Web UI** – Step-by-step wizard (Git, hosting, steps, validation) for setting up and validating your map project
8
+ - **Map listing** – Discovers `.tmj` maps on disk with properties (name, description, image, copyright, size, last modified)
9
+ - **Uploader** – Configure and run map uploads to [map-storage](https://github.com/workadventure/map-storage); list maps from map-storage for self-hosted flows
10
+ - **Static assets** – Serves public assets, tilesets, and compiled JS; transforms and serves TypeScript under `/src` (esbuild) for browser scripts
11
+ - **Express app** – CORS, JSON body parsing, cache headers; can be mounted in another app or run standalone via Vite
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @workadventure/map-starter-kit-core
17
+ ```
18
+
19
+ **Peer / consumer:** The built server expects `express` to be available at runtime. For TypeScript consumers, `@types/express` is used for the exported `Application` type.
20
+
21
+ ## Usage
22
+
23
+ ### As a dependency (programmatic)
24
+
25
+ Use the built Express app in your own server:
26
+
27
+ ```ts
28
+ import core from "@workadventure/map-starter-kit-core/dist/server.js";
29
+
30
+ const app = core.default; // or core.viteNodeApp
31
+
32
+ // Mount or start your server
33
+ app.listen(3000, () => console.log("Listening on 3000"));
34
+ ```
35
+
36
+ Types are provided: `core` is typed as `{ default: Application; viteNodeApp: Application }` (see `types/server.d.ts`).
37
+
38
+ ### Development server (standalone)
39
+
40
+ From the **map-starter-kit** repo (or a project that uses this package as the core):
41
+
42
+ ```bash
43
+ npm run dev
44
+ ```
45
+
46
+ Runs the Vite dev server with vite-plugin-node (Express). Opens the app at the configured host (e.g. `http://localhost:5173/`).
47
+
48
+ ### Build for production
49
+
50
+ ```bash
51
+ npm run build
52
+ ```
53
+
54
+ - Runs `tsc` (type-check only; `noEmit: true` in tsconfig)
55
+ - Builds the server bundle with Vite into `dist/server.js`
56
+ - Copies `types/server.d.ts` to `dist/server.d.ts` for published types
57
+
58
+ ## Project structure
59
+
60
+ ```
61
+ map-starter-kit-core/
62
+ ├── src/
63
+ │ ├── server.ts # Express app entry (CORS, static, routes)
64
+ │ ├── getCoreRoot.ts # Resolve core package root (cwd vs package dir)
65
+ │ ├── controllers/
66
+ │ │ ├── FrontController.ts # HTML pages (Mustache): /, step1-git, step2-hosting, step3-*, step4-*
67
+ │ │ ├── MapController.ts # /maps/list – list .tmj maps with properties
68
+ │ │ └── UploaderController.ts # /uploader/* – configure, status, maps-storage-list, upload
69
+ │ └── views/ # Mustache HTML templates
70
+ │ ├── index.html
71
+ │ ├── step1-git.html … step4-validated-selfhosted.html
72
+ ├── public/ # Static assets (images, styles, etc.)
73
+ ├── types/
74
+ │ └── server.d.ts # Module declaration for dist/server.js (copied to dist on build)
75
+ ├── dist/ # Build output (server.js, server.d.ts, assets)
76
+ ├── vite.config.ts
77
+ ├── tsconfig.json
78
+ └── package.json
79
+ ```
80
+
81
+ ## API / Routes
82
+
83
+ | Method | Path | Description |
84
+ |--------|------|-------------|
85
+ | **Front (HTML)** | | |
86
+ | GET | `/` | Home (index) |
87
+ | GET | `/step1-git` | Step 1 – Git |
88
+ | GET | `/step2-hosting` | Step 2 – Hosting |
89
+ | GET | `/step3-steps` | Step 3 – Steps |
90
+ | GET | `/step3-steps-selfhosted` | Step 3 – Self-hosted |
91
+ | GET | `/step4-validated` | Step 4 – Validated |
92
+ | GET | `/step4-validated-selfhosted` | Step 4 – Validated (self-hosted) |
93
+ | **Maps** | | |
94
+ | GET | `/maps/list` | List `.tmj` maps with properties (path, mapName, mapImage, size, lastModified, etc.) |
95
+ | **Uploader** | | |
96
+ | POST | `/uploader/configure` | Configure MAP_STORAGE (body: `mapStorageUrl`, `mapStorageApiKey`, `uploadDirectory`) |
97
+ | GET | `/uploader/status` | Current config status (e.g. presence of `.env.secret`) |
98
+ | GET | `/uploader/maps-storage-list` | List maps from map-storage (for self-hosted step 4) |
99
+ | POST | `/uploader/upload` | Run the upload (uses config from `.env.secret`) |
100
+
101
+ Static and special paths:
102
+
103
+ - `/public/*` – Static files from core’s `public/`
104
+ - `/assets/*` – From project’s `dist/assets/`
105
+ - `/tilesets/*` – From project’s `tilesets/`
106
+ - `/src/*.ts` – Served as compiled JS (esbuild), e.g. for browser scripts using WorkAdventure APIs
107
+
108
+ ## Configuration
109
+
110
+ ### Uploader (MAP_STORAGE)
111
+
112
+ Configure via **POST `/uploader/configure`** with:
113
+
114
+ - `mapStorageUrl` – map-storage base URL
115
+ - `mapStorageApiKey` – API key for map-storage
116
+ - `uploadDirectory` – Local directory to upload from
117
+
118
+ This writes (or updates) a secret file (e.g. `.env.secret` or `src/.env.secret` depending on route) used by the upload and maps-storage-list endpoints. Do not commit this file.
119
+
120
+ ### Core root
121
+
122
+ `getCoreRoot()` resolves the root of the core package:
123
+
124
+ - When run from the **project root** (e.g. map-starter-kit): `process.cwd()`
125
+ - When run from **packages/map-starter-kit-core** or **node_modules**: the package directory
126
+
127
+ So templates and `public` are always loaded from the core package, while maps, `.env`, and `tilesets` stay in the project root.
128
+
129
+ ## Scripts
130
+
131
+ | Script | Command | Description |
132
+ |--------|---------|-------------|
133
+ | `dev` | `vite` | Start dev server (Express via vite-plugin-node) |
134
+ | `build` | `tsc && vite build && node -e "…"` | Type-check, build server to `dist/`, copy `server.d.ts` |
135
+
136
+ ## Releasing
137
+
138
+ Releases are automated with **semantic-release** and **GitHub Actions**:
139
+
140
+ - **Workflow:** `.github/workflows/release.yml`
141
+ - **Trigger:** Push to `main` or `master`
142
+ - **Conventions:** [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `BREAKING CHANGE:`) determine the next version; a release is published only when there are relevant commits.
143
+ - **Artifacts:** GitHub Release + **npm** publish of `@workadventure/map-starter-kit-core`.
144
+
145
+ **npm auth (after classic token deprecation):**
146
+
147
+ - **Recommended:** [Trusted Publishing (OIDC)](https://docs.npmjs.com/trusted-publishers) for this repo and workflow (no long-lived token).
148
+ - **Alternative:** Create a **granular access token** on [npm](https://www.npmjs.com/settings/~/tokens), then set the **NPM_TOKEN** secret in the repo.
149
+
150
+ ## Tech stack
151
+
152
+ - **Runtime:** Node.js, Express 5
153
+ - **Build:** TypeScript 5, Vite 7, vite-plugin-node
154
+ - **Templates:** Mustache
155
+ - **Release:** semantic-release
156
+
157
+ ## License
158
+
159
+ MIT. See [LICENSE](LICENSE).
160
+
161
+ ## Links
162
+
163
+ - **Repository:** [github.com/workadventure/map-starter-kit-core](https://github.com/workadventure/map-starter-kit-core)
164
+ - **Issues:** [github.com/workadventure/map-starter-kit-core/issues](https://github.com/workadventure/map-starter-kit-core/issues)
165
+ - **npm:** [@workadventure/map-starter-kit-core](https://www.npmjs.com/package/@workadventure/map-starter-kit-core)
@@ -0,0 +1,168 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
+ <meta name="robots" content="noindex">
9
+ <meta name="title" content="WorkAdventure Starter Kit">
10
+
11
+ <link href="public/styles/styles.css" rel="stylesheet">
12
+
13
+ <title>WorkAdventure build your map</title>
14
+ <link rel="icon" href="public/images/favicon.svg" type="image/svg+xml">
15
+ <script type="module">
16
+ document.addEventListener("DOMContentLoaded", (event) => {
17
+ // Load index.js to have access to getMapsList
18
+ import('/public/assets/js/index.js').then(() => {
19
+ loadTMJ();
20
+ });
21
+ });
22
+
23
+ async function loadTMJ() {
24
+ try {
25
+ // Get the list of maps from the API
26
+ const maps = await window.getMapsList();
27
+
28
+ // Retrieve map images for background fade
29
+ const mapImages = maps
30
+ .map(map => {
31
+ if (map.mapImage) {
32
+ return map.mapImage.startsWith('http') ? map.mapImage : `/${map.mapImage}`;
33
+ }
34
+ return null;
35
+ })
36
+ .filter(img => img !== null);
37
+
38
+ // Create background image fade
39
+ if (mapImages.length > 0) {
40
+ await window.createBackgroundImageFade(mapImages);
41
+ }
42
+
43
+ // Mustache template for a map card
44
+ const cardTemplate = `
45
+ <div class="map-cover" style="background-image: url('{{mapImageUrl}}');"></div>
46
+ <div class="map-date">
47
+ Last edit: {{lastModifiedFormatted}}
48
+ </div>
49
+ <div class="map-name">
50
+ {{mapName}}
51
+ </div>
52
+ <div class="map-detail">
53
+ <div class="map-file">
54
+ <strong>{{filename}}</strong>.tmj
55
+ </div>
56
+ <div class="map-weight">
57
+ <strong>{{size}}</strong>
58
+ <span style="opacity: .5">Mo</span>
59
+ </div>
60
+ </div>
61
+ <div class="map-desc">
62
+ {{mapDescription}}
63
+ </div>
64
+ <div class="map-testurl">
65
+ <a href="#" class="btn" data-map-path="{{path}}">Test my map</a>
66
+ </div>
67
+ `;
68
+
69
+ // Prepare data for Mustache
70
+ const mapsData = maps.map(map => {
71
+ // Build the image URL - use the first available image or a default image
72
+ const mapImageUrl = map.mapImage
73
+ ? (map.mapImage.startsWith('http') ? map.mapImage : `/${map.mapImage}`)
74
+ : (mapImages.length > 0 ? mapImages[0] : 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="1620" height="1024"><rect fill="%231b2a41" width="100%" height="100%"/></svg>');
75
+
76
+ return {
77
+ ...map,
78
+ mapImageUrl: mapImageUrl,
79
+ mapDescription: map.mapDescription || 'No description available'
80
+ };
81
+ });
82
+
83
+ // Render each map with Mustache and inject them into the container
84
+ const mainElement = document.querySelector('main');
85
+ if (mainElement) {
86
+ // Clear existing content
87
+ mainElement.innerHTML = '';
88
+
89
+ // Create a section for each map
90
+ mapsData.forEach(map => {
91
+ const section = document.createElement('section');
92
+ section.className = 'card-map';
93
+ section.innerHTML = Mustache.render(cardTemplate, map);
94
+
95
+ // Add an event handler for the "Test my map" button
96
+ const testBtn = section.querySelector('.map-testurl a');
97
+ if (testBtn) {
98
+ testBtn.addEventListener('click', (e) => {
99
+ e.preventDefault();
100
+ const host = window.location.host;
101
+ let path = window.location.pathname;
102
+ if (path.endsWith('index.html')) {
103
+ path = path.substr(0, path.length - 'index.html'.length);
104
+ }
105
+ const instanceId = Math.random().toString(36).substring(2, 15);
106
+ const url = `https://play.workadventu.re/_/${instanceId}/${host}${path}${map.path}`;
107
+ window.open(url, '_blank');
108
+ });
109
+ }
110
+
111
+ mainElement.appendChild(section);
112
+ });
113
+ }
114
+ } catch (error) {
115
+ console.error('Error loading maps:', error);
116
+ }
117
+ }
118
+ </script>
119
+ </head>
120
+
121
+ <body>
122
+ <div class="content">
123
+ <header>
124
+ <div class="logo">
125
+ <a href="https://workadventu.re/" target="_blank" title="Workadventure">
126
+ <img src="public/images/logo.svg" alt="Workadventure logo" height="36" />
127
+ </a>
128
+ </div>
129
+ <div style="flex-grow: 1;"></div>
130
+ <div class="socials">
131
+ <a href="https://discord.gg/G6Xh9ZM9aR" target="_blank" title="discord">
132
+ <img src="/public/images/brand-discord.svg" alt="discord">
133
+ </a>
134
+ <a href="https://github.com/thecodingmachine/workadventure" target="_blank" title="github">
135
+ <img src="/public/images/brand-github.svg" alt="github">
136
+ </a>
137
+ <a href="https://www.youtube.com/channel/UCXJ9igV-kb9gw1ftR33y5tA" target="_blank" title="youtube">
138
+ <img src="/public/images/brand-youtube.svg" alt="youtube">
139
+ </a>
140
+ <a href="https://twitter.com/Workadventure_" target="_blank" title="twitter">
141
+ <img src="/public/images/brand-x.svg" alt="X">
142
+ </a>
143
+ <a href="https://www.linkedin.com/company/workadventu-re" target="_blank" title="linkedin">
144
+ <img src="/public/images/brand-linkedin.svg" alt="linkedin">
145
+ </a>
146
+ </div>
147
+ <div class="btn-header-wrapper">
148
+ <a href="https://discord.gg/G6Xh9ZM9aR" target="_blank" class="btn btn-light">Talk to the community</a>
149
+ <a href="https://docs.workadventu.re/map-building/" target="_blank" class="btn">Documentation</a>
150
+ </div>
151
+ </header>
152
+ <main>
153
+ <!-- Map cards will be injected here dynamically by Mustache -->
154
+ </main>
155
+ <div class="button-wrapper">
156
+ <div style="flex-grow: 1;">
157
+ </div>
158
+ <div>
159
+ <a href="step1-git">
160
+ Publish
161
+ </a>
162
+ </div>
163
+ </div>
164
+ </div>
165
+ <div class="bg"></div>
166
+ </body>
167
+
168
+ </html>
@@ -0,0 +1,154 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
+ <meta name="robots" content="noindex">
9
+ <meta name="title" content="WorkAdventure Starter Kit">
10
+
11
+ <link href="public/styles/styles.css" rel="stylesheet">
12
+
13
+ <title>WorkAdventure build your map</title>
14
+ <link rel="icon" href="public/images/favicon.svg" type="image/svg+xml">
15
+ <script type="module">
16
+ document.addEventListener("DOMContentLoaded", (event) => {
17
+ // Load index.js to have access to getMapsList
18
+ import('/public/assets/js/index.js').then(() => {
19
+ window.createBackgroundImageFade();
20
+ });
21
+ });
22
+ </script>
23
+ </head>
24
+
25
+ <body>
26
+ <div class="content">
27
+ <header>
28
+ <div class="logo">
29
+ <a href="https://workadventu.re/" target="_blank" title="Workadventure">
30
+ <img src="public/images/logo.svg" alt="Workadventure logo" height="36" />
31
+ </a>
32
+ </div>
33
+ <div style="flex-grow: 1;"></div>
34
+ <div class="socials">
35
+ <a href="https://discord.gg/G6Xh9ZM9aR" target="_blank" title="discord">
36
+ <img src="/public/images/brand-discord.svg" alt="discord">
37
+ </a>
38
+ <a href="https://github.com/thecodingmachine/workadventure" target="_blank" title="github">
39
+ <img src="/public/images/brand-github.svg" alt="github">
40
+ </a>
41
+ <a href="https://www.youtube.com/channel/UCXJ9igV-kb9gw1ftR33y5tA" target="_blank" title="youtube">
42
+ <img src="/public/images/brand-youtube.svg" alt="youtube">
43
+ </a>
44
+ <a href="https://twitter.com/Workadventure_" target="_blank" title="twitter">
45
+ <img src="/public/images/brand-x.svg" alt="X">
46
+ </a>
47
+ <a href="https://www.linkedin.com/company/workadventu-re" target="_blank" title="linkedin">
48
+ <img src="/public/images/brand-linkedin.svg" alt="linkedin">
49
+ </a>
50
+ </div>
51
+ <div class="btn-header-wrapper">
52
+ <a href="https://discord.gg/G6Xh9ZM9aR" target="_blank" class="btn btn-light">Talk to the community</a>
53
+ <a href="https://docs.workadventu.re/map-building/" target="_blank" class="btn">Documentation</a>
54
+ </div>
55
+ </header>
56
+ <main>
57
+ <section class="form-center">
58
+ <h1>
59
+ How do you want to publish your map?
60
+ </h1>
61
+ <div class="sub-heading">
62
+ Choose the workflow that best fits your team and your way of working.
63
+ </div>
64
+ <div class="radio-wrapper">
65
+ <label class="radio-card">
66
+ <input name="advanced" class="radio" type="radio">
67
+ <div class="card-details">
68
+ <svg width="39" height="39" viewBox="0 0 39 39" fill="none" xmlns="http://www.w3.org/2000/svg">
69
+ <path d="M8.125 19.5L16.25 27.625L32.5 11.375" stroke="#4156F6" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
70
+ </svg>
71
+
72
+ <h2>
73
+ Advanced publishing
74
+ </h2>
75
+ <div>
76
+ <strong>Designed for teams using Git and file versioning.</strong>
77
+ Full control over your files and collaboration workflow.
78
+ </div>
79
+ </div>
80
+ </label>
81
+ <label class="radio-card">
82
+ <input name="advanced" class="radio" type="radio" checked>
83
+ <div class="card-details">
84
+ <svg width="39" height="39" viewBox="0 0 39 39" fill="none" xmlns="http://www.w3.org/2000/svg">
85
+ <path d="M8.125 19.5L16.25 27.625L32.5 11.375" stroke="#4156F6" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
86
+ </svg>
87
+
88
+ <h2>
89
+ Recommended publishing
90
+ </h2>
91
+ <div>
92
+ <strong>The easiest and fastest way to publish your map.</strong>
93
+ No technical setup required. Ideal for getting started quickly.
94
+ </div>
95
+ </div>
96
+ </label>
97
+ </div>
98
+
99
+ </section>
100
+ </main>
101
+ <div class="button-wrapper">
102
+ <div>
103
+ <a href="/" class="btn btn-ghost">
104
+ Previous
105
+ </a>
106
+ </div>
107
+ <div style="flex-grow: 1;">
108
+ </div>
109
+ <div>
110
+ <a href="step2-hosting" class="btn btn-secondary">
111
+ Start configuration
112
+ </a>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ <div class="bg"></div>
117
+ <script>
118
+ // Get radio buttons by finding the label containing "Advanced publishing"
119
+ const radioButtons = document.querySelectorAll('input[name="advanced"]');
120
+ const startConfigButton = document.querySelector('a[href="step2-hosting"]');
121
+ const docUrl = "https://docs.workadventu.re/map-building/tiled-editor/publish/wa-hosted";
122
+
123
+ // Find Advanced publishing radio button by checking parent label text
124
+ let advancedPublishingRadio = null;
125
+ radioButtons.forEach(radio => {
126
+ const label = radio.closest('label');
127
+ if (label && label.textContent.includes('Advanced publishing')) {
128
+ advancedPublishingRadio = radio;
129
+ }
130
+ });
131
+
132
+ // Function to update button href based on selection
133
+ function updateButtonHref() {
134
+ // Check if Advanced publishing is selected
135
+ if (advancedPublishingRadio && advancedPublishingRadio.checked) {
136
+ startConfigButton.href = docUrl;
137
+ startConfigButton.target = "_blank";
138
+ } else {
139
+ startConfigButton.href = "step2-hosting";
140
+ startConfigButton.removeAttribute("target");
141
+ }
142
+ }
143
+
144
+ // Add event listeners to all radio buttons
145
+ radioButtons.forEach(radio => {
146
+ radio.addEventListener('change', updateButtonHref);
147
+ });
148
+
149
+ // Initialize on page load
150
+ updateButtonHref();
151
+ </script>
152
+ </body>
153
+
154
+ </html>
@@ -0,0 +1,153 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
+ <meta name="robots" content="noindex">
9
+ <meta name="title" content="WorkAdventure Starter Kit">
10
+
11
+ <link href="public/styles/styles.css" rel="stylesheet">
12
+
13
+ <title>WorkAdventure build your map</title>
14
+ <link rel="icon" href="public/images/favicon.svg" type="image/svg+xml">
15
+ </head>
16
+
17
+ <body>
18
+ <div class="content">
19
+ <header>
20
+ <div class="logo">
21
+ <a href="https://workadventu.re/" target="_blank" title="Workadventure">
22
+ <img src="public/images/logo.svg" alt="Workadventure logo" height="36" />
23
+ </a>
24
+ </div>
25
+ <div style="flex-grow: 1;"></div>
26
+ <div class="socials">
27
+ <a href="https://discord.gg/G6Xh9ZM9aR" target="_blank" title="discord">
28
+ <img src="/public/images/brand-discord.svg" alt="discord">
29
+ </a>
30
+ <a href="https://github.com/thecodingmachine/workadventure" target="_blank" title="github">
31
+ <img src="/public/images/brand-github.svg" alt="github">
32
+ </a>
33
+ <a href="https://www.youtube.com/channel/UCXJ9igV-kb9gw1ftR33y5tA" target="_blank" title="youtube">
34
+ <img src="/public/images/brand-youtube.svg" alt="youtube">
35
+ </a>
36
+ <a href="https://twitter.com/Workadventure_" target="_blank" title="twitter">
37
+ <img src="/public/images/brand-x.svg" alt="X">
38
+ </a>
39
+ <a href="https://www.linkedin.com/company/workadventu-re" target="_blank" title="linkedin">
40
+ <img src="/public/images/brand-linkedin.svg" alt="linkedin">
41
+ </a>
42
+ </div>
43
+ <div class="btn-header-wrapper">
44
+ <a href="#" class="btn btn-light">Talk to the community</a>
45
+ <a href="#" class="btn">Documentation</a>
46
+ </div>
47
+ <script type="module">
48
+ document.addEventListener("DOMContentLoaded", (event) => {
49
+ // Load index.js to have access to getMapsList
50
+ import('/public/assets/js/index.js').then(() => {
51
+ window.createBackgroundImageFade();
52
+ });
53
+ });
54
+ </script>
55
+ </header>
56
+ <main>
57
+ <section class="form-center">
58
+ <h1>
59
+ Which version of WorkAdventure do you use?
60
+ </h1>
61
+ <div class="sub-heading">
62
+ Choose the setup that matches how your WorkAdventure instance is running. This will help us adapt the publishing process to your setup.
63
+ </div>
64
+ <div class="radio-wrapper">
65
+ <label class="radio-card">
66
+ <input name="advanced" class="radio" type="radio">
67
+ <div class="card-details">
68
+ <svg width="39" height="39" viewBox="0 0 39 39" fill="none" xmlns="http://www.w3.org/2000/svg">
69
+ <path d="M8.125 19.5L16.25 27.625L32.5 11.375" stroke="#4156F6" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
70
+ </svg>
71
+
72
+ <h2>
73
+ I use self-hosted
74
+ </h2>
75
+ <div>
76
+ Your map is published on your own WorkAdventure instance.
77
+ <strong>You manage the hosting, configuration, and updates yourself.</strong>
78
+ </div>
79
+ </div>
80
+ </label>
81
+ <label class="radio-card">
82
+ <input name="advanced" class="radio" type="radio">
83
+ <div class="card-details">
84
+ <svg width="39" height="39" viewBox="0 0 39 39" fill="none" xmlns="http://www.w3.org/2000/svg">
85
+ <path d="M8.125 19.5L16.25 27.625L32.5 11.375" stroke="#4156F6" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
86
+ </svg>
87
+
88
+ <h2>
89
+ I use SaaS version
90
+ </h2>
91
+ <div>
92
+ Your map is published on the WorkAdventure platform.
93
+ <strong>We handle hosting, updates, and infrastructure for you.</strong>
94
+ </div>
95
+ </div>
96
+ </label>
97
+ </div>
98
+
99
+ </section>
100
+ </main>
101
+ <div class="button-wrapper">
102
+ <div>
103
+ <a href="step1-git" class="btn btn-ghost">
104
+ Previous
105
+ </a>
106
+ </div>
107
+ <div style="flex-grow: 1;">
108
+ </div>
109
+ <div>
110
+ <a href="step3-steps" class="btn btn-secondary">
111
+ Configure
112
+ </a>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ <div class="bg"></div>
117
+ <script>
118
+ // Get radio buttons by finding the label containing "I use self-hosted"
119
+ const radioButtons = document.querySelectorAll('input[name="advanced"]');
120
+ const configureButton = document.querySelector('a[href="step3-steps"]');
121
+
122
+ // Find "I use self-hosted" radio button by checking parent label text
123
+ let selfHostedRadio = null;
124
+ radioButtons.forEach(radio => {
125
+ const label = radio.closest('label');
126
+ if (label && label.textContent.includes('I use self-hosted')) {
127
+ selfHostedRadio = radio;
128
+ }
129
+ });
130
+
131
+ // Function to update button href based on selection
132
+ function updateButtonHref() {
133
+ // Check if "I use self-hosted" is selected
134
+ if (selfHostedRadio && selfHostedRadio.checked) {
135
+ configureButton.href = "step3-steps-selfhosted";
136
+ configureButton.removeAttribute("target");
137
+ } else {
138
+ configureButton.href = "step3-steps";
139
+ configureButton.removeAttribute("target");
140
+ }
141
+ }
142
+
143
+ // Add event listeners to all radio buttons
144
+ radioButtons.forEach(radio => {
145
+ radio.addEventListener('change', updateButtonHref);
146
+ });
147
+
148
+ // Initialize on page load
149
+ updateButtonHref();
150
+ </script>
151
+ </body>
152
+
153
+ </html>