PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.10
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.10
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
← All changes | includes/games/window.php +120 -59 0.9.71.1.10 View file →
@@ -1,7 +1,7 @@
1 1 <?php
2 2 /**
3 - * Desktop Mode — Games: hub window + desktop icon registration.
3 + * OpenStation — Games: hub window + desktop icon registration.
4 4 *
5 5 * Native window with id `desktop-mode-games` — the "Games folder"
6 6 * fixture on the wallpaper. The template body is a static skeleton
7 7 * (a game grid + a detail panel, Steam-library style) that the JS
@@ -9,32 +9,82 @@
9 9 * registry; selecting a game reveals its description, Play +
10 10 * Challenge actions, its scoreboard, and its challenges below.
11 11 *
12 12 * Both registrations are filterable via
13 - * `desktop_mode_games_window_args` / `desktop_mode_games_icon_args`,
13 + * `openstation_games_window_args` / `openstation_games_icon_args`,
14 14 * mirroring the Recycle Bin.
15 15 *
16 - * @package WPDesktopMode
17 - * @since 0.9.6
16 + * @package OpenStation
18 17 */
19 18
20 19 defined( 'ABSPATH' ) || exit;
21 20
22 21 /**
22 + * The stylesheet handles a game window needs, hub or no hub.
23 + *
24 + * Set once while the Games window is registered — after the
25 + * `openstation_games_window_args` filter, so it includes the built-in
26 + * games' own sheets and any a plugin appended — and read back when the
27 + * shell config is assembled.
28 + *
29 + * These ride the hub window as companion styles, which is right when
30 + * the hub is what opened. It is not the only way in: the challenge
31 + * toast's "Accept & Play" is built to work with the hub closed, solo
32 + * mode boots straight to `?openstation_solo=os-game-<id>`, and
33 + * `wp.os.games.launch()` is documented for plugin authors. Each of
34 + * those reaches `launchGame()` in the shell bundle without the hub
35 + * window ever existing, and the game then paints unstyled.
36 + *
37 + * @param string[]|null $set Handles to store, when registering.
38 + * @return string[] The stored handles.
39 + */
40 +function openstation_games_style_handles( $set = null ) {
41 + static $handles = array();
42 + if ( null !== $set ) {
43 + $handles = array_values( array_unique( array_filter( array_map( 'strval', (array) $set ) ) ) );
44 + }
45 + return $handles;
46 +}
47 +
48 +/**
23 49 * The shared gamepad SVG used by the window icon and the desktop
24 50 * icon.
25 51 *
26 - * @since 0.9.6
52 + * Drawn in `currentColor`, which is what makes it a silhouette:
53 + * `isSilhouetteSvg()` in `src/icon.ts` looks for exactly that token
54 + * and, finding it, paints the art as a CSS mask instead of a
55 + * background-image, so it takes whatever colour the surface is
56 + * already using for text.
27 57 *
58 + * This icon used to be the only fixed-colour one in the shell, in
59 + * four hues (`#6c5ce7`, white, `#ffd166`, `#06d6a0`) that belong to
60 + * no palette the plugin ships. Two things followed from that. It
61 + * could not invert on a light title bar or a light desktop theme,
62 + * because a background-image has no colour to inherit. And under a
63 + * desktop theme's icon tint it collapsed outright: that path runs
64 + * `applyIconMask()`, which keeps only the artwork's alpha, and every
65 + * pixel of the old gamepad was opaque, so the d-pad and the buttons
66 + * vanished into a featureless blob.
67 + *
68 + * Redrawn as an outlined body with the controls knocked into it, the
69 + * detail is carried by negative space rather than by colour, so it
70 + * survives both. Held to five elements because it renders as small as
71 + * 20px in the dock: body, two d-pad bars, two buttons.
72 + *
28 73 * @return string Raw `<svg>` markup.
29 74 */
30 -function desktop_mode_games_icon_svg() {
75 +function openstation_games_icon_svg() {
31 76 return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">'
32 - . '<path fill="#6c5ce7" d="M18 16h28a16 16 0 0 1 16 16v10a10 10 0 0 1-18.3 5.6L39.9 42H24.1l-3.8 5.6A10 10 0 0 1 2 42V32a16 16 0 0 1 16-16z"/>'
33 - . '<rect x="12" y="28" width="14" height="5" rx="2.5" fill="#ffffff"/>'
34 - . '<rect x="16.5" y="23.5" width="5" height="14" rx="2.5" fill="#ffffff"/>'
35 - . '<circle cx="43" cy="27" r="3.4" fill="#ffd166"/>'
36 - . '<circle cx="50" cy="34" r="3.4" fill="#06d6a0"/>'
77 + // The body: outlined, so what sits inside it reads as detail
78 + // rather than as more fill.
79 + . '<path d="M21 21h22a13 13 0 0 1 12.6 9.8l2.8 11.2a7.5 7.5 0 0 1-13.6 5.8L40.5 41h-17l-4.3 6.8A7.5 7.5 0 0 1 5.6 42l2.8-11.2A13 13 0 0 1 21 21z" fill="none" stroke="currentColor" stroke-width="3" stroke-linejoin="round" stroke-linecap="round"/>'
80 + // D-pad, two crossed bars sharing a centre.
81 + . '<rect x="14" y="28.5" width="14" height="4.6" rx="2.3" fill="currentColor"/>'
82 + . '<rect x="18.7" y="23.8" width="4.6" height="14" rx="2.3" fill="currentColor"/>'
83 + // Face buttons, offset on the diagonal the way a real pad has
84 + // them. Two, not four: four would not separate at 20px.
85 + . '<circle cx="40.5" cy="34" r="3.1" fill="currentColor"/>'
86 + . '<circle cx="47.5" cy="28.5" r="3.1" fill="currentColor"/>'
37 87 . '</svg>';
38 88 }
39 89
40 90 /**
@@ -39,13 +89,11 @@
39 89
40 90 /**
41 91 * Whether the current user can use desktop games.
42 92 *
43 - * @since 0.9.6
44 - *
45 93 * @return bool
46 94 */
47 -function desktop_mode_games_user_can_use() {
95 +function openstation_games_user_can_use() {
48 96 $can = is_user_logged_in() && current_user_can( 'read' );
49 97
50 98 /**
51 99 * Filter whether the current user can see the Games window,
@@ -50,31 +98,27 @@
50 98 /**
51 99 * Filter whether the current user can see the Games window,
52 100 * icon, and play games.
53 101 *
54 - * @since 0.9.6
55 - *
56 102 * @param bool $can Default: logged-in + `read` capability.
57 103 */
58 - return (bool) apply_filters( 'desktop_mode_games_user_can_use', $can );
104 + return (bool) apply_filters( 'openstation_games_user_can_use', $can );
59 105 }
60 106
61 107 /**
62 108 * Echoes the Games window's template body.
63 109 *
64 - * The `data-desktop-mode-games-*` hooks are the contract the JS
110 + * The `data-os-games-*` hooks are the contract the JS
65 111 * render callback relies on — keep them intact (or rename via the
66 112 * filter) when customizing the layout.
67 - *
68 - * @since 0.9.6
69 113 */
70 -function desktop_mode_games_render_template() {
114 +function openstation_games_render_template() {
71 115 ob_start();
72 116 ?>
73 - <div class="desktop-mode-games" data-desktop-mode-games-root>
74 - <div class="desktop-mode-games__library">
75 - <div class="desktop-mode-games__grid" data-desktop-mode-games-grid role="listbox" aria-label="<?php esc_attr_e( 'Games', 'desktop-mode' ); ?>"></div>
76 - <div class="desktop-mode-games__detail" data-desktop-mode-games-detail hidden></div>
117 + <div class="desktop-mode-games" data-os-games-root>
118 + <div class="os-games__library">
119 + <div class="os-games__grid" data-os-games-grid role="listbox" aria-label="<?php esc_attr_e( 'Games', 'desktop-mode' ); ?>"></div>
120 + <div class="os-games__detail" data-os-games-detail hidden></div>
77 121 </div>
78 122 </div>
79 123 <?php
80 124 $html = (string) ob_get_clean();
@@ -81,17 +125,15 @@
81 125
82 126 /**
83 127 * Filter the Games window's template HTML.
84 128 *
85 - * Keep the `data-desktop-mode-games-*` hooks intact so the JS
129 + * Keep the `data-os-games-*` hooks intact so the JS
86 130 * render callback can find its mount points.
87 131 *
88 - * @since 0.9.6
89 - *
90 132 * @param string $html Default template HTML.
91 133 */
92 - $filtered = (string) apply_filters( 'desktop_mode_games_template_html', $html );
93 - echo wp_kses( $filtered, desktop_mode_native_window_allowed_html() );
134 + $filtered = (string) apply_filters( 'openstation_games_template_html', $html );
135 + echo wp_kses( $filtered, openstation_native_window_allowed_html() );
94 136 }
95 137
96 138 /**
97 139 * Register the Games window + desktop icon on `init`.
@@ -97,49 +139,71 @@
97 139 * Register the Games window + desktop icon on `init`.
98 140 *
99 141 * Priority 20, after the native-window registry bootstraps — same
100 142 * timing as the Recycle Bin.
101 - *
102 - * @since 0.9.6
103 143 */
104 -function desktop_mode_games_register_window() {
105 - if ( ! desktop_mode_games_user_can_use() ) {
144 +function openstation_games_register_window() {
145 + if ( ! openstation_games_user_can_use() ) {
106 146 return;
107 147 }
108 148
109 - $icon_uri = 'data:image/svg+xml;base64,' . base64_encode( desktop_mode_games_icon_svg() );
149 + $icon_uri = 'data:image/svg+xml;base64,' . base64_encode( openstation_games_icon_svg() );
110 150
111 151 $window_args = array(
112 152 'title' => __( 'Games', 'desktop-mode' ),
113 153 'icon' => $icon_uri,
114 - 'template' => 'desktop_mode_games_render_template',
154 + 'template' => 'openstation_games_render_template',
115 155 'script' => 'desktop-mode-games',
156 + // Companion styles load with the games bundle on first open.
157 + // Every game window (`os-game-<id>`) is opened by
158 + // `launchGame()`, which lives in that bundle — so a sheet
159 + // riding it here is guaranteed in the tab before any game
160 + // paints. Built-in games append their own via the
161 + // `openstation_games_window_args` filter below.
162 + 'styles' => array( 'desktop-mode-games' ),
116 163 'width' => 900,
117 164 'height' => 600,
118 165 'min_width' => 560,
119 166 'min_height' => 400,
120 - 'placement' => 'dock',
167 + // No dock tile from the window registration: the desktop icon
168 + // below is this app's one launcher. Registering both used to
169 + // mint two entries for one app, each with its own default, and
170 + // the dock painted a tile while Preferences said "On the
171 + // desktop". The navigation model collapses them either way —
172 + // this keeps Games matching how My WordPress and Corkboard
173 + // already register.
174 + 'placement' => 'none',
121 175 );
122 176
123 177 /**
124 178 * Filter the args used to register the Games native window.
125 179 *
126 - * @since 0.9.6
127 - *
128 - * @param array $window_args Args passed to `desktop_mode_register_window()`.
180 + * @param array $window_args Args passed to `openstation_register_window()`.
129 181 */
130 - $window_args = (array) apply_filters( 'desktop_mode_games_window_args', $window_args );
182 + $window_args = (array) apply_filters( 'openstation_games_window_args', $window_args );
131 183
132 - $registered = desktop_mode_register_window( 'desktop-mode-games', $window_args );
184 + // Remember the finished style list — base sheet plus whatever the
185 + // built-in games and any plugin appended through the filter above.
186 + // A game window does NOT always arrive through the hub: the
187 + // challenge toast's "Accept & Play" is designed to work with the
188 + // hub closed, solo mode boots straight into
189 + // `?openstation_solo=os-game-<id>`, and `wp.os.games.launch()` is
190 + // documented for plugins. In each of those, `launchGame()` runs
191 + // from the SHELL bundle's copy, the hub window never opens, and its
192 + // companion sheets never load — the HUD paints as raw text. The
193 + // shell needs the list to inject them on demand.
194 + openstation_games_style_handles( $window_args['styles'] );
195 +
196 + $registered = openstation_register_window( 'desktop-mode-games', $window_args );
133 197 if ( is_wp_error( $registered ) ) {
134 198 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
135 - error_log( '[desktop-mode] Games window registration failed: ' . $registered->get_error_message() );
199 + error_log( '[openstation] Games window registration failed: ' . $registered->get_error_message() );
136 200 return;
137 201 }
138 202
139 203 $icon_args = array(
140 204 'title' => __( 'Games', 'desktop-mode' ),
141 - 'icon_svg' => desktop_mode_games_icon_svg(),
205 + 'icon_svg' => openstation_games_icon_svg(),
142 206 'window' => 'desktop-mode-games',
143 207 'position' => 85,
144 208 );
145 209
@@ -145,34 +209,30 @@
145 209
146 210 /**
147 211 * Filter the args used to register the Games desktop icon.
148 212 *
149 - * @since 0.9.6
150 - *
151 - * @param array $icon_args Args passed to `desktop_mode_register_icon()`.
213 + * @param array $icon_args Args passed to `openstation_register_icon()`.
152 214 */
153 - $icon_args = (array) apply_filters( 'desktop_mode_games_icon_args', $icon_args );
215 + $icon_args = (array) apply_filters( 'openstation_games_icon_args', $icon_args );
154 216
155 - desktop_mode_register_icon( 'desktop-mode-games', $icon_args );
217 + openstation_register_icon( 'desktop-mode-games', $icon_args );
156 218 }
157 -add_action( 'init', 'desktop_mode_games_register_window', 20 );
219 +add_action( 'init', 'openstation_games_register_window', 20 );
158 220
159 221 /**
160 222 * Localize REST endpoints for the JS bundle.
161 223 *
162 - * The bundle reads its config off `window.desktopModeGamesConfig`
224 + * The bundle reads its config off `window.openStationGamesConfig`
163 225 * and never hardcodes URLs.
164 - *
165 - * @since 0.9.6
166 226 */
167 -function desktop_mode_games_localize_config() {
168 - if ( ! desktop_mode_games_user_can_use() ) {
227 +function openstation_games_localize_config() {
228 + if ( ! openstation_games_user_can_use() ) {
169 229 return;
170 230 }
171 231
172 232 wp_localize_script(
173 233 'desktop-mode-games',
174 - 'desktopModeGamesConfig',
234 + 'openStationGamesConfig',
175 235 array(
176 236 'restNonce' => wp_create_nonce( 'wp_rest' ),
177 237 'gamesUrlBase' => esc_url_raw( rest_url( 'desktop-mode/v1/games' ) ),
178 238 'challengesUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/games/challenges' ) ),
@@ -178,8 +238,9 @@
178 238 'challengesUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/games/challenges' ) ),
179 239 'usersSearchUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/games/users/search' ) ),
180 240 )
181 241 );
182 -
183 - wp_enqueue_style( 'desktop-mode-games' );
184 242 }
185 -add_action( 'admin_enqueue_scripts', 'desktop_mode_games_localize_config', 30 );
243 +// Priority 5 for the same reason as the recycle bin: the lazy-load payload is
244 +// built at priority 10, and localize data attached after that never reaches a
245 +// bundle that loads on window open.
246 +add_action( 'admin_enqueue_scripts', 'openstation_games_localize_config', 5 );