Skip to content

Commit d64be08

Browse files
authored
Iframe Embed: Mobile Controls & Full Screen support (#323)
* Added support for the mobile touchpad and fullscreen on the embed * Added the mobile iframe embed gif * Added the new iframeEmbed gif
1 parent 03731a4 commit d64be08

12 files changed

+170
-25
lines changed

demo/iframe/components/About.svelte

+1
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,6 @@
4343
4444
.about a, .about a:visited {
4545
color: #b5cbfc;
46+
word-break: break-all;
4647
}
4748
</style>

demo/iframe/components/ControlsBar.svelte

+60-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
<script>
2-
import {isPlaying, setStatus, status, triggerSaveState, showLoadState, showAbout} from '../stores.js';
2+
import {
3+
isPlaying,
4+
setStatus,
5+
status,
6+
triggerSaveState,
7+
showLoadState,
8+
showAbout,
9+
isTouchPadVisible,
10+
isFullScreen
11+
} from '../stores.js';
312
import PlayIcon from './icons/PlayIcon.svelte';
413
import PauseIcon from './icons/PauseIcon.svelte';
514
import SaveIcon from './icons/SaveIcon.svelte';
615
import LoadIcon from './icons/LoadIcon.svelte';
716
import AboutIcon from './icons/AboutIcon.svelte';
17+
import ShowGamePadIcon from './icons/ShowGamePadIcon.svelte';
18+
import HideGamePadIcon from './icons/HideGamePadIcon.svelte';
19+
import FullScreenIcon from './icons/FullScreenIcon.svelte';
20+
import ExitFullScreenIcon from './icons/ExitFullScreenIcon.svelte';
821
922
// Subscribe to our current status
1023
let displayStatus = false;
@@ -47,9 +60,32 @@
4760
showLoadState();
4861
};
4962
63+
const handleGamePad = () => {
64+
if ($isTouchPadVisible) {
65+
isTouchPadVisible.set(false);
66+
} else {
67+
isTouchPadVisible.set(true);
68+
}
69+
};
70+
5071
const handleAbout = () => {
5172
showAbout();
5273
};
74+
75+
const handleFullScreen = async () => {
76+
if ($isFullScreen) {
77+
isFullScreen.set(false);
78+
document.exitFullscreen();
79+
} else {
80+
try {
81+
await document.documentElement.requestFullscreen();
82+
isFullScreen.set(true);
83+
} catch(e) {
84+
console.error(e);
85+
setStatus('Error, could not fullscreen!');
86+
}
87+
}
88+
};
5389
</script>
5490

5591
<footer class="controls-bar">
@@ -80,11 +116,31 @@
80116
</button>
81117
</li>
82118

119+
<li>
120+
<button class="icon-button" on:click={handleGamePad}>
121+
{#if $isTouchPadVisible}
122+
<HideGamePadIcon />
123+
{:else}
124+
<ShowGamePadIcon />
125+
{/if}
126+
</button>
127+
</li>
128+
83129
<li>
84130
<button class="icon-button" on:click={handleAbout}>
85131
<AboutIcon />
86132
</button>
87133
</li>
134+
135+
<li>
136+
<button class="icon-button" on:click={handleFullScreen}>
137+
{#if $isFullScreen}
138+
<FullScreenIcon />
139+
{:else}
140+
<ExitFullScreenIcon />
141+
{/if}
142+
</button>
143+
</li>
88144
</ul>
89145
</footer>
90146

@@ -101,7 +157,9 @@
101157
transition: transform 0.5s;
102158
}
103159
104-
:global(html):hover .controls-bar, :global(body):hover .controls-bar {
160+
:global(html):hover .controls-bar,
161+
:global(body):hover .controls-bar,
162+
:global(.touchpad-visible) .controls-bar {
105163
transform: translateY(-50px);
106164
}
107165

demo/iframe/components/Modal.svelte

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@
3636

3737
<style>
3838
dialog {
39-
width: 100%;
39+
width: calc(100% - 50px);
4040
height: 800px;
4141
max-width: 800px;
4242
max-height: calc(100% - 100px);
43-
margin: 10px;
43+
margin-top: 10px;
4444
margin-left: auto;
4545
margin-right: auto;
4646

demo/iframe/components/WasmBoy.svelte

+12
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,25 @@
102102
.canvas-container {
103103
width: 100%;
104104
height: 100%;
105+
106+
background-color: #000;
105107
}
106108
107109
.canvas-container > canvas {
108110
width: 100%;
109111
height: 100%;
110112
}
111113
114+
:global(.touchpad-visible.portrait) .canvas-container > canvas {
115+
width: 100%;
116+
height: 300px;
117+
}
118+
119+
:global(.touchpad-visible.landscape) .canvas-container > canvas {
120+
width: 100%;
121+
height: calc(100% - 50px);
122+
}
123+
112124
.status {
113125
width: 100%;
114126
height: 100%;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!-- Google Material Play Icon -->
2+
<!-- https://material.io/resources/icons -->
3+
4+
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
5+
<path d="M0 0h24v24H0z" fill="none"/>
6+
<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" fill="#fff"/>
7+
</svg>
8+
9+
<style>
10+
svg {
11+
width: 100%;
12+
height: 100%;
13+
}
14+
</style>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!-- Google Material Play Icon -->
2+
<!-- https://material.io/resources/icons -->
3+
4+
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
5+
<path d="M0 0h24v24H0z" fill="none"/>
6+
<path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z" fill="#fff"/>
7+
</svg>
8+
9+
10+
<style>
11+
svg {
12+
width: 100%;
13+
height: 100%;
14+
}
15+
</style>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!-- Google Material Play Icon -->
2+
<!-- https://material.io/resources/icons -->
3+
4+
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
5+
<path d="M0 0h24v24H0z" fill="none"/>
6+
<path d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-10 7H8v3H6v-3H3v-2h3V8h2v3h3v2zm4.5 2c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm4-3c-.83 0-1.5-.67-1.5-1.5S18.67 9 19.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" fill="#fff"/>
7+
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" fill="#ff0000"/>
8+
</svg>
9+
10+
11+
<style>
12+
svg {
13+
width: 100%;
14+
height: 100%;
15+
}
16+
</style>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!-- Google Material Play Icon -->
2+
<!-- https://material.io/resources/icons -->
3+
4+
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
5+
<path d="M0 0h24v24H0z" fill="none"/>
6+
<path d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-10 7H8v3H6v-3H3v-2h3V8h2v3h3v2zm4.5 2c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm4-3c-.83 0-1.5-.67-1.5-1.5S18.67 9 19.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" fill="#fff"/>
7+
</svg>
8+
9+
<style>
10+
svg {
11+
width: 100%;
12+
height: 100%;
13+
}
14+
</style>

demo/iframe/components/touchpad/GameBoyTouchPad.svelte

+25-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script>
22
import { onMount, onDestroy } from 'svelte';
3-
import {modalStore, showTouchPad} from '../../stores.js';
3+
import {modalStore, isTouchPadVisible} from '../../stores.js';
44
55
import GameBoyDpad from './GameBoyDpad.svelte';
66
import GameBoyLetterButton from './GameBoyLetterButton.svelte';
@@ -14,8 +14,20 @@
1414
});
1515
onMount(mountResolve);
1616
17-
const removeInputCallbacks = [];
17+
// Subscribe to whether or not the touchpad is shown
18+
isTouchPadVisible.subscribe((value) => {
19+
// Get our document class list
20+
const documentClassList = document.documentElement.classList;
21+
22+
if (value) {
23+
documentClassList.add('touchpad-visible');
24+
} else {
25+
documentClassList.remove('touchpad-visible');
26+
}
27+
});
28+
1829
30+
const removeInputCallbacks = [];
1931
const addWasmBoyInputs = async () => {
2032
2133
// Wait to mount
@@ -54,17 +66,15 @@
5466
})
5567
</script>
5668

57-
{#if $modalStore === 0 && $showTouchPad === true}
58-
<div class="mobile-controls">
59-
<div class="gameboy-input">
60-
<div id="gameboy-dpad"><GameBoyDpad /></div>
61-
<div id="gameboy-a"><GameBoyLetterButton content="A" /></div>
62-
<div id="gameboy-b"><GameBoyLetterButton content="B" /></div>
63-
<div id="gameboy-start"><GameBoyWordButton content="start" /></div>
64-
<div id="gameboy-select"><GameBoyWordButton content="select" /></div>
65-
</div>
69+
<div class="mobile-controls" style={$modalStore === 0 && $isTouchPadVisible === true ? '': 'display: none'}>
70+
<div class="gameboy-input">
71+
<div id="gameboy-dpad"><GameBoyDpad /></div>
72+
<div id="gameboy-a"><GameBoyLetterButton content="A" /></div>
73+
<div id="gameboy-b"><GameBoyLetterButton content="B" /></div>
74+
<div id="gameboy-start"><GameBoyWordButton content="start" /></div>
75+
<div id="gameboy-select"><GameBoyWordButton content="select" /></div>
6676
</div>
67-
{/if}
77+
</div>
6878

6979
<style>
7080
/*GENERAL*/
@@ -189,7 +199,7 @@
189199
position: absolute;
190200
z-index: 1;
191201
top: calc(50% - 13vw);
192-
left: 5%;
202+
left: 3%;
193203
}
194204
195205
:global(html.landscape) #gameboy-b {
@@ -198,7 +208,7 @@
198208
position: absolute;
199209
z-index: 1;
200210
top: calc(50% - 5vw);
201-
right: 15%;
211+
right: 18%;
202212
}
203213
204214
:global(html.landscape) #gameboy-a {
@@ -207,7 +217,7 @@
207217
position: absolute;
208218
z-index: 1;
209219
top: calc(50% - 13vw);
210-
right: 1%;
220+
right: 3%;
211221
}
212222
213223
:global(html.landscape) #gameboy-select {

demo/iframe/scripts/layout-change.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,17 @@ const handleLayoutChange = () => {
5050

5151
// Add all Media query based on mobile vs desktop
5252
documentClassList.add('mobile');
53-
if (landscape || isWide) {
53+
54+
if (landscape) {
5455
documentClassList.add('landscape');
55-
} else {
56+
documentClassList.remove('portrait');
57+
} else if (portrait) {
58+
documentClassList.add('portrait');
5659
documentClassList.remove('landscape');
5760
}
58-
if (portrait) {
59-
documentClassList.add('portrait');
60-
} else {
61+
62+
if (!landscape && !portrait && isWide) {
63+
documentClassList.add('landscape');
6164
documentClassList.remove('portrait');
6265
}
6366
};

demo/iframe/stores.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,6 @@ export const romName = writable(params.get('rom-name'));
4747

4848
// Handle showing and hiding the mobile controls
4949
const isUserAgentMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
50-
export const showTouchPad = writable(!!isUserAgentMobile);
50+
export const isTouchPadVisible = writable(!!isUserAgentMobile);
51+
52+
export const isFullScreen = writable(false);

docs/images/iframeEmbed.gif

1.06 MB
Loading

0 commit comments

Comments
 (0)