better UI + AppIcon
@@ -21,6 +21,7 @@
|
|||||||
"core-js-pure",
|
"core-js-pure",
|
||||||
"esbuild",
|
"esbuild",
|
||||||
"protobufjs",
|
"protobufjs",
|
||||||
|
"sharp",
|
||||||
"workerd"
|
"workerd"
|
||||||
],
|
],
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
|
|||||||
13
packages/native-app/.expo/README.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
> Why do I have a folder named ".expo" in my project?
|
||||||
|
|
||||||
|
The ".expo" folder is created when an Expo project is started using "expo start" command.
|
||||||
|
|
||||||
|
> What do the files contain?
|
||||||
|
|
||||||
|
- "devices.json": contains information about devices that have recently opened this project. This is used to populate the "Development sessions" list in your development builds.
|
||||||
|
- "settings.json": contains the server configuration that is used to serve the application manifest.
|
||||||
|
|
||||||
|
> Should I commit the ".expo" folder?
|
||||||
|
|
||||||
|
No, you should not share the ".expo" folder. It does not contain any information that is relevant for other developers working on the project, it is specific to your machine.
|
||||||
|
Upon project creation, the ".expo" folder is already added to your ".gitignore" file.
|
||||||
3
packages/native-app/.expo/devices.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"devices": []
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -9,7 +9,7 @@ android {
|
|||||||
|
|
||||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation project(':capacitor-screen-orientation')
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
@@ -8,7 +7,6 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
@@ -16,12 +14,12 @@
|
|||||||
android:theme="@style/AppTheme.NoActionBarLaunch"
|
android:theme="@style/AppTheme.NoActionBarLaunch"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
@@ -29,12 +27,17 @@
|
|||||||
android:authorities="${applicationId}.fileprovider"
|
android:authorities="${applicationId}.fileprovider"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:grantUriPermissions="true">
|
android:grantUriPermissions="true">
|
||||||
<meta-data
|
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
|
||||||
android:resource="@xml/file_paths"></meta-data>
|
|
||||||
</provider>
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.software.leanback"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.touchscreen"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
<!-- Permissions -->
|
<!-- Permissions -->
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 2.7 KiB |
@@ -1,5 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
<background>
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
<inset android:drawable="@mipmap/ic_launcher_background" android:inset="16.7%" />
|
||||||
|
</background>
|
||||||
|
<foreground>
|
||||||
|
<inset android:drawable="@mipmap/ic_launcher_foreground" android:inset="16.7%" />
|
||||||
|
</foreground>
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
<background>
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
<inset android:drawable="@mipmap/ic_launcher_background" android:inset="16.7%" />
|
||||||
|
</background>
|
||||||
|
<foreground>
|
||||||
|
<inset android:drawable="@mipmap/ic_launcher_foreground" android:inset="16.7%" />
|
||||||
|
</foreground>
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 531 B |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 573 B |
|
After Width: | Height: | Size: 277 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 868 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 850 B |
|
After Width: | Height: | Size: 350 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 697 B |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 5.0 KiB |
@@ -1,3 +1,6 @@
|
|||||||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||||
include ':capacitor-android'
|
include ':capacitor-android'
|
||||||
project(':capacitor-android').projectDir = new File('../../../node_modules/@capacitor/android/capacitor')
|
project(':capacitor-android').projectDir = new File('../../../node_modules/@capacitor/android/capacitor')
|
||||||
|
|
||||||
|
include ':capacitor-screen-orientation'
|
||||||
|
project(':capacitor-screen-orientation').projectDir = new File('../../../node_modules/@capacitor/screen-orientation/android')
|
||||||
|
|||||||
20
packages/play-standalone/assets/icon.svg
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<svg
|
||||||
|
width="512"
|
||||||
|
height="512"
|
||||||
|
viewBox="0 0 26.458333 26.458333"
|
||||||
|
version="1.1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<rect x="0" y="0" width="26.458333" height="26.458333" fill="#09090b"/>
|
||||||
|
<g transform="translate(13.2291665, 13.2291665) scale(0.60) translate(-13.2291665, -13.2291665)">
|
||||||
|
<path
|
||||||
|
d="M 1.5344249,1.5344211 V 9.2976453 C 10.141372,9.3506226 17.107729,16.31697 17.160697,24.923917 h 7.763224 V 1.5344211 H 17.26052 V 7.6582313 L 17.095435,7.5123325 C 12.813137,3.6822243 7.2773806,1.558425 1.5344327,1.5344191 Z"
|
||||||
|
fill="#FFFFFF"></path>
|
||||||
|
<path
|
||||||
|
d="m 1.5344249,10.321451 v 7.472042 c 3.9146312,0.04963 7.080792,3.215792 7.1304217,7.130424 H 16.136889 C 16.086774,16.878739 9.5796027,10.37157 1.5344249,10.321451 Z"
|
||||||
|
fill="#FFFFFF"></path>
|
||||||
|
<path
|
||||||
|
d="m 1.5344249,18.699055 v 6.224862 H 7.7592875 C 7.7148345,21.504871 4.9534705,18.743512 1.5344249,18.699055 Z"
|
||||||
|
fill="#FFFFFF"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
BIN
packages/play-standalone/icons/icon-128.webp
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
packages/play-standalone/icons/icon-192.webp
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
packages/play-standalone/icons/icon-256.webp
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
packages/play-standalone/icons/icon-48.webp
Normal file
|
After Width: | Height: | Size: 702 B |
BIN
packages/play-standalone/icons/icon-512.webp
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
packages/play-standalone/icons/icon-72.webp
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
packages/play-standalone/icons/icon-96.webp
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
@@ -5,18 +5,23 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"build": "astro build",
|
"build": "astro build",
|
||||||
"build:cap": "astro build && npx cap copy",
|
"build:cap": "astro build && bunx cap copy",
|
||||||
"preview": "astro preview",
|
"preview": "astro preview",
|
||||||
"astro": "astro",
|
"astro": "astro",
|
||||||
"sync:android": "npm run build && npx cap sync android"
|
"sync:android": "bun run build && bunx cap sync android"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@astrojs/node": "9.5.0",
|
||||||
"@capacitor/android": "^7.4.3",
|
"@capacitor/android": "^7.4.3",
|
||||||
"@capacitor/cli": "^7.4.3",
|
"@capacitor/cli": "^7.4.3",
|
||||||
"@capacitor/core": "^7.4.3",
|
"@capacitor/core": "^7.4.3",
|
||||||
"@capacitor/ios": "^7.4.3",
|
"@capacitor/ios": "^7.4.3",
|
||||||
"@astrojs/node": "9.5.0",
|
"@capacitor/screen-orientation": "^7.0.2",
|
||||||
"@nestri/input": "*",
|
"@nestri/input": "*",
|
||||||
"astro": "5.15.1"
|
"astro": "5.15.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@capacitor/assets": "^3.0.5",
|
||||||
|
"sharp": "^0.34.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
46
packages/play-standalone/public/manifest.webmanifest
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-48.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "48x48",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-72.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "72x72",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-96.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "96x96",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-128.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "128x128",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-192.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-256.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "256x256",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-512.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,138 +1,109 @@
|
|||||||
---
|
---
|
||||||
import { ClientRouter } from "astro:transitions";
|
import { ClientRouter } from "astro:transitions";
|
||||||
import { navigate } from "astro:transitions/client";
|
import { navigate } from "astro:transitions/client";
|
||||||
|
import DefaultLayout from "../layouts/DefaultLayout.astro";
|
||||||
|
import "../styles/index.css";
|
||||||
---
|
---
|
||||||
<html lang="en">
|
|
||||||
<head>
|
<DefaultLayout>
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
<title>Nestri Play</title>
|
|
||||||
<ClientRouter />
|
<ClientRouter />
|
||||||
<style>
|
<div class="page-container">
|
||||||
body {
|
<div class="grid-system">
|
||||||
font-family: sans-serif;
|
<div class="grid-root">
|
||||||
display: flex;
|
<div class="grid-block">
|
||||||
justify-content: center;
|
<div class="stack">
|
||||||
align-items: center;
|
<div class="header-stack">
|
||||||
height: 100vh;
|
<h2>Nestri Play</h2>
|
||||||
margin: 0;
|
<p class="subtitle">
|
||||||
}
|
Enter your room details to join the stream.
|
||||||
form {
|
</p>
|
||||||
display: flex;
|
</div>
|
||||||
flex-direction: column;
|
|
||||||
gap: 1rem;
|
<form id="join-form">
|
||||||
padding: 2rem;
|
<div class="form-stack">
|
||||||
border: 1px solid #ccc;
|
<div class="input-group">
|
||||||
border-radius: 8px;
|
<input
|
||||||
}
|
type="text"
|
||||||
div {
|
id="room"
|
||||||
display: flex;
|
name="room"
|
||||||
flex-direction: column;
|
required
|
||||||
}
|
list="room-list"
|
||||||
label {
|
placeholder="Room Name"
|
||||||
margin-bottom: 0.5rem;
|
>
|
||||||
}
|
<datalist id="room-list"></datalist>
|
||||||
input {
|
</div>
|
||||||
padding: 0.5rem;
|
|
||||||
border: 1px solid #ccc;
|
<div class="input-group">
|
||||||
border-radius: 4px;
|
<input
|
||||||
}
|
type="text"
|
||||||
button {
|
id="peerURL"
|
||||||
padding: 0.75rem;
|
name="peerURL"
|
||||||
border: none;
|
required
|
||||||
border-radius: 4px;
|
list="peerURL-list"
|
||||||
background-color: #007bff;
|
placeholder="Peer URL"
|
||||||
color: white;
|
>
|
||||||
cursor: pointer;
|
<datalist id="peerURL-list"></datalist>
|
||||||
}
|
</div>
|
||||||
button:hover {
|
|
||||||
background-color: #0056b3;
|
<button type="submit" id="submit-btn">Join Stream</button>
|
||||||
}
|
</div>
|
||||||
</style>
|
</form>
|
||||||
</head>
|
</div>
|
||||||
<body>
|
</div>
|
||||||
<form id="join-form">
|
</div>
|
||||||
<h1>Nestri Play</h1>
|
|
||||||
<div>
|
|
||||||
<label for="room">Room</label>
|
|
||||||
<input type="text" id="room" name="room" required list="room-list">
|
|
||||||
<datalist id="room-list"></datalist>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
</div>
|
||||||
<label for="peerURL">peerURL</label>
|
</DefaultLayout>
|
||||||
<input type="text" id="peerURL" name="peerURL" required list="peerURL-list">
|
|
||||||
<datalist id="peerURL-list"></datalist>
|
|
||||||
</div>
|
|
||||||
<button type="submit">Join</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { navigate } from "astro:transitions/client";
|
import { navigate } from "astro:transitions/client";
|
||||||
|
|
||||||
const roomInput = document.getElementById('room') as HTMLInputElement;
|
const roomInput = document.getElementById('room') as HTMLInputElement;
|
||||||
const peerURLInput = document.getElementById('peerURL') as HTMLInputElement;
|
const peerURLInput = document.getElementById('peerURL') as HTMLInputElement;
|
||||||
const roomList = document.getElementById('room-list');
|
const roomList = document.getElementById('room-list');
|
||||||
const peerURLList = document.getElementById('peerURL-list');
|
const peerURLList = document.getElementById('peerURL-list');
|
||||||
|
|
||||||
// Load values from cookies
|
// Load values from localStorage
|
||||||
function getCookie(name) {
|
const storedRooms = JSON.parse(localStorage.getItem('nestri-rooms') || '[]');
|
||||||
const value = `; ${document.cookie}`;
|
const storedPeerURLs = JSON.parse(localStorage.getItem('nestri-peerURLs') || '[]');
|
||||||
const parts = value.split(`; ${name}=`);
|
|
||||||
if (parts.length === 2) {
|
|
||||||
const cookieValue = parts.pop()?.split(';').shift();
|
|
||||||
return cookieValue ? decodeURIComponent(cookieValue) : undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCookie(name, value, days) {
|
if (roomList) {
|
||||||
const d = new Date();
|
storedRooms.forEach(room => {
|
||||||
d.setTime(d.getTime() + (days*24*60*60*1000));
|
const option = document.createElement('option');
|
||||||
const expires = "expires="+ d.toUTCString();
|
option.value = room;
|
||||||
document.cookie = name + "=" + encodeURIComponent(value) + ";" + expires + ";path=/";
|
roomList.appendChild(option);
|
||||||
}
|
|
||||||
|
|
||||||
const storedRooms = JSON.parse(getCookie('nestri-rooms') || '[]');
|
|
||||||
const storedPeerURLs = JSON.parse(getCookie('nestri-peerURLs') || '[]');
|
|
||||||
|
|
||||||
if (roomList) {
|
|
||||||
storedRooms.forEach(room => {
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.value = room;
|
|
||||||
roomList.appendChild(option);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peerURLList) {
|
|
||||||
storedPeerURLs.forEach(peerURL => {
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.value = peerURL;
|
|
||||||
peerURLList.appendChild(option);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (storedRooms.length > 0 && roomInput) {
|
|
||||||
roomInput.value = storedRooms[0];
|
|
||||||
}
|
|
||||||
if (storedPeerURLs.length > 0 && peerURLInput) {
|
|
||||||
peerURLInput.value = storedPeerURLs[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('join-form')?.addEventListener('submit', function(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
const room = roomInput.value;
|
|
||||||
const peerURL = peerURLInput.value;
|
|
||||||
|
|
||||||
// Save values to cookies
|
|
||||||
const newRooms = [room, ...storedRooms.filter(r => r !== room)].slice(0, 10);
|
|
||||||
const newPeerURLs = [peerURL, ...storedPeerURLs.filter(p => p !== peerURL)].slice(0, 10);
|
|
||||||
|
|
||||||
setCookie('nestri-rooms', JSON.stringify(newRooms), 365);
|
|
||||||
setCookie('nestri-peerURLs', JSON.stringify(newPeerURLs), 365);
|
|
||||||
|
|
||||||
if (room && peerURL) {
|
|
||||||
navigate(`/play/index.html?peerURL=${encodeURIComponent(peerURL)}#${room}`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
}
|
||||||
</body>
|
|
||||||
</html>
|
if (peerURLList) {
|
||||||
|
storedPeerURLs.forEach(peerURL => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = peerURL;
|
||||||
|
peerURLList.appendChild(option);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (storedRooms.length > 0 && roomInput) {
|
||||||
|
roomInput.value = storedRooms[0];
|
||||||
|
}
|
||||||
|
if (storedPeerURLs.length > 0 && peerURLInput) {
|
||||||
|
peerURLInput.value = storedPeerURLs[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('join-form')?.addEventListener('submit', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const room = roomInput.value;
|
||||||
|
const peerURL = peerURLInput.value;
|
||||||
|
|
||||||
|
// Save values to localStorage
|
||||||
|
const newRooms = [room, ...storedRooms.filter(r => r !== room)].slice(0, 10);
|
||||||
|
const newPeerURLs = [peerURL, ...storedPeerURLs.filter(p => p !== peerURL)].slice(0, 10);
|
||||||
|
|
||||||
|
localStorage.setItem('nestri-rooms', JSON.stringify(newRooms));
|
||||||
|
localStorage.setItem('nestri-peerURLs', JSON.stringify(newPeerURLs));
|
||||||
|
|
||||||
|
if (room && peerURL) {
|
||||||
|
navigate(`/play/index.html?peerURL=${encodeURIComponent(peerURL)}#${room}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -24,6 +24,22 @@ if (envs_map.size > 0) {
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Mouse, Keyboard, Controller, WebRTCStream } from "@nestri/input";
|
import { Mouse, Keyboard, Controller, WebRTCStream } from "@nestri/input";
|
||||||
|
import { ScreenOrientation } from '@capacitor/screen-orientation';
|
||||||
|
|
||||||
|
// Lock to landscape
|
||||||
|
const lockOrientation = async () => {
|
||||||
|
try {
|
||||||
|
await ScreenOrientation.lock({ orientation: 'landscape' });
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Screen orientation lock failed:", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
lockOrientation();
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', () => {
|
||||||
|
ScreenOrientation.unlock();
|
||||||
|
});
|
||||||
|
|
||||||
const ENVS = document.getElementById("ENVS")!.dataset.envs as string;
|
const ENVS = document.getElementById("ENVS")!.dataset.envs as string;
|
||||||
let ENVS_MAP: Map<string, string | undefined> | null = null;
|
let ENVS_MAP: Map<string, string | undefined> | null = null;
|
||||||
if (ENVS && ENVS.length > 0) {
|
if (ENVS && ENVS.length > 0) {
|
||||||
|
|||||||
144
packages/play-standalone/src/styles/index.css
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
:root {
|
||||||
|
--color-background: #191919;
|
||||||
|
--color-surface: #252525;
|
||||||
|
--color-primary: #f97316; /* Orange-500 */
|
||||||
|
--color-primary-hover: #ea580c; /* Orange-600 */
|
||||||
|
--color-text-main: #ffffff;
|
||||||
|
--color-text-muted: #a1a1aa;
|
||||||
|
--color-border: #3f3f46;
|
||||||
|
color-scheme: dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
padding: 2rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-system {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-root {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.grid-root {
|
||||||
|
grid-template-columns: repeat(12, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-block {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.grid-block {
|
||||||
|
grid-column: 4 / 10; /* Center in the middle 6 columns */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stack {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3rem;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 500px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stack {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0;
|
||||||
|
color: var(--color-text-main);
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-stack {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
background-color: var(--color-surface);
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--color-text-main);
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
box-sizing: border-box;
|
||||||
|
caret-color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-primary);
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
color: var(--color-text-main);
|
||||||
|
}
|
||||||
|
|
||||||
|
input::placeholder {
|
||||||
|
color: #52525b;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 9999px; /* Full rounded like signup */
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: var(--color-primary-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Autofill styling fix for dark mode */
|
||||||
|
input:-webkit-autofill,
|
||||||
|
input:-webkit-autofill:hover,
|
||||||
|
input:-webkit-autofill:focus,
|
||||||
|
input:-webkit-autofill:active{
|
||||||
|
-webkit-box-shadow: 0 0 0 30px var(--color-surface) inset !important;
|
||||||
|
-webkit-text-fill-color: var(--color-text-main) !important;
|
||||||
|
}
|
||||||