windowpp 0.1.2 → 0.1.3

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.
@@ -0,0 +1,24 @@
1
+ /* @refresh reload */
2
+ import './index.css';
3
+ import { render } from 'solid-js/web';
4
+ import { HashRouter, Route } from '@solidjs/router';
5
+ import 'solid-devtools';
6
+
7
+ import Layout from './Layout';
8
+ import App from './App';
9
+ import Settings from './pages/Settings';
10
+
11
+ const root = document.getElementById('root');
12
+
13
+ if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
14
+ throw new Error(
15
+ 'Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?',
16
+ );
17
+ }
18
+
19
+ render(() => (
20
+ <HashRouter root={Layout}>
21
+ <Route path="/" component={App} />
22
+ <Route path="/settings" component={Settings} />
23
+ </HashRouter>
24
+ ), root!);
@@ -0,0 +1,47 @@
1
+ import { useLocation } from '@solidjs/router';
2
+ import { createSignal, onMount } from 'solid-js';
3
+
4
+ export default function About() {
5
+ const location = useLocation();
6
+ const [href, setHref] = createSignal('');
7
+
8
+ onMount(() => {
9
+ setHref(window.location.href);
10
+ });
11
+
12
+ return (
13
+ <div class="p-10 max-w-2xl mx-auto text-zinc-100">
14
+ <h1 class="text-3xl font-bold mb-3">About — Routing Test</h1>
15
+ <p class="mb-4 text-zinc-400">
16
+ This page demonstrates <strong class="text-white">hash-based client-side routing</strong> with{' '}
17
+ <code class="bg-zinc-800 px-1 rounded text-blue-300">@solidjs/router</code>.
18
+ </p>
19
+
20
+ <div class="rounded-lg bg-zinc-900 border border-zinc-700 p-4 font-mono text-sm space-y-1">
21
+ <div>
22
+ <span class="text-zinc-500">pathname: </span>
23
+ <span class="text-green-400">{location.pathname}</span>
24
+ </div>
25
+ <div>
26
+ <span class="text-zinc-500">search: </span>
27
+ <span class="text-yellow-400">{location.search || '(none)'}</span>
28
+ </div>
29
+ <div>
30
+ <span class="text-zinc-500">hash: </span>
31
+ <span class="text-blue-400">{location.hash || '(none)'}</span>
32
+ </div>
33
+ <div>
34
+ <span class="text-zinc-500">href: </span>
35
+ <span class="text-zinc-300 break-all">{href()}</span>
36
+ </div>
37
+ </div>
38
+
39
+ <p class="mt-5 text-sm text-zinc-500">
40
+ Hash routing works out-of-the-box with embedded binary assets — the
41
+ scheme handler returns <code class="bg-zinc-800 px-1 rounded">index.html</code> for
42
+ any path, and the <code class="bg-zinc-800 px-1 rounded">#fragment</code> is
43
+ resolved entirely in the browser, never sent to the server.
44
+ </p>
45
+ </div>
46
+ );
47
+ }
@@ -0,0 +1,37 @@
1
+ import { useNavigate } from '@solidjs/router';
2
+
3
+ export default function Settings() {
4
+ const navigate = useNavigate();
5
+
6
+ return (
7
+ <div class="min-h-screen bg-[radial-gradient(circle_at_top,#f8fafc,#e2e8f0_40%,#cbd5e1)] px-6 py-8 text-slate-900">
8
+ <div class="mx-auto max-w-6xl">
9
+
10
+ {/* Header Card */}
11
+ <div class="mb-8 rounded-4xl border border-white/70 bg-white/80 p-8 shadow-2xl shadow-slate-400/20 backdrop-blur">
12
+ <div class="flex items-center justify-between">
13
+ <div>
14
+ <p class="mb-2 text-sm font-semibold uppercase tracking-[0.3em] text-slate-500">WindowPP Playground</p>
15
+ <h1 class="text-4xl font-bold tracking-tight text-slate-900">Settings</h1>
16
+ </div>
17
+ <button
18
+ class="flex items-center gap-1.5 rounded-2xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-600 hover:bg-slate-100 transition-colors select-none"
19
+ onClick={() => navigate('/')}
20
+ >
21
+ <svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 text-slate-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
22
+ <path d="M19 12H5M12 5l-7 7 7 7"/>
23
+ </svg>
24
+ <span class="font-semibold text-slate-800">Back to App</span>
25
+ </button>
26
+ </div>
27
+ </div>
28
+
29
+ {/* Placeholder content */}
30
+ <div class="rounded-4xl border border-white/70 bg-white/80 p-8 shadow-2xl shadow-slate-400/20 backdrop-blur text-slate-500 text-sm">
31
+ Settings content goes here.
32
+ </div>
33
+
34
+ </div>
35
+ </div>
36
+ );
37
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ // General
4
+ "jsx": "preserve",
5
+ "jsxImportSource": "solid-js",
6
+ "target": "ESNext",
7
+
8
+ // Modules
9
+ "allowSyntheticDefaultImports": true,
10
+ "esModuleInterop": true,
11
+ "isolatedModules": true,
12
+ "module": "ESNext",
13
+ "moduleResolution": "bundler",
14
+ "noEmit": true,
15
+
16
+ // Type Checking & Safety
17
+ "strict": true,
18
+ "types": ["vite/client"]
19
+ }
20
+ }
@@ -0,0 +1,27 @@
1
+ import { resolve } from 'node:path';
2
+ import tailwindcss from '@tailwindcss/vite';
3
+ import { defineConfig } from 'vite';
4
+ import solidPlugin from 'vite-plugin-solid';
5
+
6
+ const REPO_ROOT = '{{REPO_ROOT}}';
7
+
8
+ export default defineConfig({
9
+ plugins: [solidPlugin(), tailwindcss()],
10
+ base: './',
11
+ resolve: {
12
+ alias: {
13
+ // '@wpp/Foo/bar' resolves to <framework>/src/Foo/bar
14
+ // Used by templates that import bridge APIs: @wpp/AppData/API/AppData, etc.
15
+ '@wpp': resolve(REPO_ROOT, 'src'),
16
+ },
17
+ },
18
+ server: {
19
+ port: 3000,
20
+ fs: {
21
+ allow: [REPO_ROOT],
22
+ },
23
+ },
24
+ build: {
25
+ target: 'esnext',
26
+ },
27
+ });
@@ -0,0 +1,224 @@
1
+ // ============================================================================
2
+ // main.cpp — WindowPP WebView Example
3
+ //
4
+ // Build modes
5
+ // ───────────
6
+ // Release (cmake --build build --config Release):
7
+ // Frontend is compiled into the binary via embedded_assets.cpp.
8
+ // The app serves assets from the "app" custom URI scheme — no server needed.
9
+ //
10
+ // Dev (set env var WPP_DEV_URL before launching):
11
+ // WPP_DEV_URL=http://localhost:3000 ./{{CMAKE_TARGET}}
12
+ // The app loads from the Vite dev server instead; hot-reload works normally.
13
+ // ============================================================================
14
+
15
+ #include <windowpp/windowpp.h>
16
+ #include "AppData/appdata_bridge.h"
17
+ #include "AppData/appdata_manager.h"
18
+ #include "FileSystem/filesystem_bridge.h"
19
+ #include "Input/input_bridge.h"
20
+ #include "platform/platform_bridge.h"
21
+ #include <cstdlib> // std::getenv
22
+ #include <memory>
23
+ #include <vector>
24
+
25
+ #ifdef WPP_EMBEDDED_ASSETS
26
+ #include "embedded_assets.h"
27
+ #endif
28
+
29
+ int main() {
30
+ wpp::AppConfig app_config;
31
+ app_config.name = "WindowPP Dev";
32
+ app_config.quit_on_last_close = true;
33
+ app_config.tray_enabled = true;
34
+
35
+ wpp::AppDataManager app_data(app_config.name);
36
+
37
+ auto app = wpp::create_app(app_config);
38
+
39
+ wpp::WindowConfig main_win;
40
+ main_win.id = "main";
41
+ main_win.title = "WindowPP - Dev View";
42
+ main_win.width = 1280;
43
+ main_win.height = 800;
44
+ main_win.center = true;
45
+ main_win.frameless = true;
46
+ main_win.transparent = true;
47
+ main_win.background = {0, 0, 0, 0};
48
+
49
+ main_win.webview.enabled = true;
50
+ main_win.file_drop = true;
51
+ main_win.scrollbars = false;
52
+
53
+ // Keep all WebView profile data (cookies, cache, localStorage) in the
54
+ // OS-standard app data directory rather than next to the exe.
55
+ main_win.webview.user_data_dir = app_data.path("WebView");
56
+
57
+ wpp::Window* win = nullptr;
58
+ auto app_data_bridge = std::make_shared<wpp::appdata::AppDataBridge>(
59
+ [&win](const std::string& js) {
60
+ if (win && win->webview()) {
61
+ win->webview()->execute_script(js);
62
+ }
63
+ },
64
+ app_config.name);
65
+ auto filesystem_bridge = std::make_shared<wpp::fs::FsBridge>(
66
+ [&win](const std::string& js) {
67
+ if (win && win->webview()) {
68
+ win->webview()->execute_script(js);
69
+ }
70
+ },
71
+ [app_ptr = app.get()](std::function<void()> fn) {
72
+ app_ptr->dispatch(std::move(fn));
73
+ },
74
+ app_data.path("FileIndex"));
75
+ auto input_bridge = std::make_shared<wpp::input::InputBridge>(
76
+ [&win](const std::string& js) {
77
+ if (win && win->webview()) {
78
+ win->webview()->execute_script(js);
79
+ }
80
+ },
81
+ [app_ptr = app.get()](std::function<void()> fn) {
82
+ app_ptr->dispatch(std::move(fn));
83
+ },
84
+ main_win.id);
85
+ auto platform_bridge = std::make_shared<wpp::platform_api::PlatformBridge>(
86
+ [&win](const std::string& js) {
87
+ if (win && win->webview()) {
88
+ win->webview()->execute_script(js);
89
+ }
90
+ },
91
+ [app_ptr = app.get()](std::function<void()> fn) {
92
+ app_ptr->dispatch(std::move(fn));
93
+ },
94
+ *app,
95
+ app_config,
96
+ main_win.id);
97
+
98
+ main_win.on_created = [platform_bridge, window_id = main_win.id]() {
99
+ platform_bridge->emit_window_event("created", window_id);
100
+ };
101
+ main_win.on_shown = [platform_bridge, window_id = main_win.id]() {
102
+ platform_bridge->emit_window_event("shown", window_id);
103
+ };
104
+ main_win.on_hidden = [platform_bridge, window_id = main_win.id]() {
105
+ platform_bridge->emit_window_event("hidden", window_id);
106
+ };
107
+ main_win.on_resize = [platform_bridge, window_id = main_win.id](wpp::ResizeEvent event) {
108
+ platform_bridge->emit_resize_event(window_id, event);
109
+ };
110
+ main_win.on_move = [platform_bridge, window_id = main_win.id](wpp::MoveEvent event) {
111
+ platform_bridge->emit_move_event(window_id, event);
112
+ };
113
+ main_win.on_closed = [platform_bridge, window_id = main_win.id]() {
114
+ platform_bridge->emit_window_event("closed", window_id);
115
+ };
116
+
117
+ main_win.webview.on_message = [app_data_bridge, filesystem_bridge, input_bridge, platform_bridge](const std::string& raw) {
118
+ app_data_bridge->dispatch(raw);
119
+ filesystem_bridge->dispatch(raw);
120
+ input_bridge->dispatch(raw);
121
+ platform_bridge->dispatch(raw);
122
+ };
123
+
124
+ // Decide where to load the UI from.
125
+ const char* dev_url = std::getenv("WPP_DEV_URL");
126
+ if (dev_url && *dev_url) {
127
+ // Developer override — point at a running Vite server (or any URL).
128
+ main_win.webview.initial_url = dev_url;
129
+ } else {
130
+ #ifdef WPP_EMBEDDED_ASSETS
131
+ // Production: serve embedded Vite build from the "app://" custom scheme.
132
+ main_win.webview.custom_scheme = "app";
133
+ main_win.webview.scheme_handler =
134
+ [](const std::string& path) -> wpp::SchemeResponse {
135
+ const EmbeddedAsset* asset = find_asset(path);
136
+ if (!asset) {
137
+ // SPA fallback: unknown paths get index.html so that
138
+ // client-side routers (Solid Router, TanStack Router, etc.)
139
+ // can handle the route in JavaScript.
140
+ asset = find_asset("/index.html");
141
+ }
142
+ if (asset) {
143
+ return wpp::SchemeResponse{
144
+ std::vector<uint8_t>(asset->data, asset->data + asset->size),
145
+ asset->content_type,
146
+ 200
147
+ };
148
+ }
149
+ std::string body = "404 Not Found";
150
+ return wpp::SchemeResponse{
151
+ std::vector<uint8_t>(body.begin(), body.end()),
152
+ "text/plain",
153
+ 404
154
+ };
155
+ };
156
+ main_win.webview.initial_url = "app://localhost/index.html";
157
+ #else
158
+ // Fallback when no embedded assets were compiled in.
159
+ main_win.webview.initial_url = "http://localhost:3000";
160
+ #endif
161
+ }
162
+
163
+ win = app->create_window(main_win);
164
+
165
+ if (win && win->webview()) {
166
+ win->webview()->execute_script("window.__wpp_appdata_ready = true;");
167
+ }
168
+
169
+ // Allow the frontend to open additional windows at specific hash routes.
170
+ // The URL is computed on the JS side:
171
+ // dev: http://localhost:3000/#/route
172
+ // prod: app://localhost/index.html#/route
173
+ static int child_counter = 0;
174
+ platform_bridge->set_create_window_fn(
175
+ [&app, webview_dir = app_data.path("WebView")](
176
+ const std::string& url,
177
+ const std::string& title,
178
+ int width, int height)
179
+ {
180
+ wpp::WindowConfig child;
181
+ child.id = "child_" + std::to_string(++child_counter);
182
+ child.title = title;
183
+ child.width = width;
184
+ child.height = height;
185
+ child.center = true;
186
+ child.frameless = true;
187
+ child.transparent = true;
188
+ child.background = {0, 0, 0, 0};
189
+ child.webview.enabled = true;
190
+ child.webview.user_data_dir = webview_dir;
191
+ child.webview.initial_url = url;
192
+
193
+ // In embedded-assets mode, the child window must also register the
194
+ // custom "app://" scheme so it can serve the same SPA assets.
195
+ #ifdef WPP_EMBEDDED_ASSETS
196
+ const char* dev_env = std::getenv("WPP_DEV_URL");
197
+ if (!dev_env || !*dev_env) {
198
+ child.webview.custom_scheme = "app";
199
+ child.webview.scheme_handler =
200
+ [](const std::string& path) -> wpp::SchemeResponse {
201
+ const EmbeddedAsset* asset = find_asset(path);
202
+ if (!asset) asset = find_asset("/index.html");
203
+ if (asset) {
204
+ return wpp::SchemeResponse{
205
+ std::vector<uint8_t>(asset->data, asset->data + asset->size),
206
+ asset->content_type,
207
+ 200
208
+ };
209
+ }
210
+ std::string body = "404 Not Found";
211
+ return wpp::SchemeResponse{
212
+ std::vector<uint8_t>(body.begin(), body.end()),
213
+ "text/plain", 404
214
+ };
215
+ };
216
+ }
217
+ #endif
218
+ app->create_window(child);
219
+ });
220
+
221
+ app->run();
222
+
223
+ return 0;
224
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "{{APP_NAME}}",
3
+ "version": "0.1.0",
4
+ "description": "{{APP_TITLE}} — a WindowPP app",
5
+ "cmakeTarget": "{{CMAKE_TARGET}}",
6
+ "scripts": {
7
+ "dev": "windowpp dev",
8
+ "dev:clean": "windowpp dev --clean",
9
+ "build": "windowpp build",
10
+ "build:clean": "windowpp build --clean"
11
+ }
12
+ }
@@ -50,7 +50,10 @@ add_custom_target({{CMAKE_TARGET}}_frontend_assets ALL
50
50
  )
51
51
 
52
52
  add_executable({{CMAKE_TARGET}} main.cpp ${EMBEDDED_ASSETS_CPP})
53
- target_include_directories({{CMAKE_TARGET}} PRIVATE ${GENERATED_DIR})
53
+ target_include_directories({{CMAKE_TARGET}} PRIVATE
54
+ ${GENERATED_DIR}
55
+ "${WPP_FRAMEWORK_DIR}/src" # bridge headers: AppData/, FileSystem/, Input/, platform/
56
+ )
54
57
  target_compile_definitions({{CMAKE_TARGET}} PRIVATE WPP_EMBEDDED_ASSETS)
55
58
  target_link_libraries({{CMAKE_TARGET}} PRIVATE windowpp windowpp_deps nlohmann_json::nlohmann_json)
56
59
  add_dependencies({{CMAKE_TARGET}} {{CMAKE_TARGET}}_frontend_assets)
@@ -10,7 +10,9 @@ export default defineConfig({
10
10
  base: './',
11
11
  resolve: {
12
12
  alias: {
13
- '@wpp': resolve(REPO_ROOT, 'src/platform/API'),
13
+ // '@wpp/Foo/bar' resolves to <framework>/src/Foo/bar
14
+ // Used by templates that import bridge APIs: @wpp/AppData/API/AppData, etc.
15
+ '@wpp': resolve(REPO_ROOT, 'src'),
14
16
  },
15
17
  },
16
18
  server: {