better UI + AppIcon
@@ -21,6 +21,7 @@
|
||||
"core-js-pure",
|
||||
"esbuild",
|
||||
"protobufjs",
|
||||
"sharp",
|
||||
"workerd"
|
||||
],
|
||||
"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"
|
||||
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">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
@@ -8,7 +7,6 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<activity
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"
|
||||
android:name=".MainActivity"
|
||||
@@ -16,12 +14,12 @@
|
||||
android:theme="@style/AppTheme.NoActionBarLaunch"
|
||||
android:launchMode="singleTask"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
@@ -29,12 +27,17 @@
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths"></meta-data>
|
||||
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
<uses-feature
|
||||
android:name="android.software.leanback"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false" />
|
||||
|
||||
<!-- Permissions -->
|
||||
|
||||
<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"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background>
|
||||
<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>
|
||||
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background>
|
||||
<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>
|
||||
|
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
|
||||
include ':capacitor-android'
|
||||
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": {
|
||||
"dev": "astro dev",
|
||||
"build": "astro build",
|
||||
"build:cap": "astro build && npx cap copy",
|
||||
"build:cap": "astro build && bunx cap copy",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro",
|
||||
"sync:android": "npm run build && npx cap sync android"
|
||||
"sync:android": "bun run build && bunx cap sync android"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/node": "9.5.0",
|
||||
"@capacitor/android": "^7.4.3",
|
||||
"@capacitor/cli": "^7.4.3",
|
||||
"@capacitor/core": "^7.4.3",
|
||||
"@capacitor/ios": "^7.4.3",
|
||||
"@astrojs/node": "9.5.0",
|
||||
"@capacitor/screen-orientation": "^7.0.2",
|
||||
"@nestri/input": "*",
|
||||
"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,72 +1,61 @@
|
||||
---
|
||||
import { ClientRouter } from "astro:transitions";
|
||||
import { navigate } from "astro:transitions/client";
|
||||
import DefaultLayout from "../layouts/DefaultLayout.astro";
|
||||
import "../styles/index.css";
|
||||
---
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Nestri Play</title>
|
||||
|
||||
<DefaultLayout>
|
||||
<ClientRouter />
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 2rem;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 8px;
|
||||
}
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
label {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
input {
|
||||
padding: 0.5rem;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
button {
|
||||
padding: 0.75rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page-container">
|
||||
<div class="grid-system">
|
||||
<div class="grid-root">
|
||||
<div class="grid-block">
|
||||
<div class="stack">
|
||||
<div class="header-stack">
|
||||
<h2>Nestri Play</h2>
|
||||
<p class="subtitle">
|
||||
Enter your room details to join the stream.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form id="join-form">
|
||||
<h1>Nestri Play</h1>
|
||||
<div>
|
||||
<label for="room">Room</label>
|
||||
<input type="text" id="room" name="room" required list="room-list">
|
||||
<div class="form-stack">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text"
|
||||
id="room"
|
||||
name="room"
|
||||
required
|
||||
list="room-list"
|
||||
placeholder="Room Name"
|
||||
>
|
||||
<datalist id="room-list"></datalist>
|
||||
</div>
|
||||
<div>
|
||||
<label for="peerURL">peerURL</label>
|
||||
<input type="text" id="peerURL" name="peerURL" required list="peerURL-list">
|
||||
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text"
|
||||
id="peerURL"
|
||||
name="peerURL"
|
||||
required
|
||||
list="peerURL-list"
|
||||
placeholder="Peer URL"
|
||||
>
|
||||
<datalist id="peerURL-list"></datalist>
|
||||
</div>
|
||||
<button type="submit">Join</button>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
<button type="submit" id="submit-btn">Join Stream</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DefaultLayout>
|
||||
|
||||
<script>
|
||||
import { navigate } from "astro:transitions/client";
|
||||
|
||||
const roomInput = document.getElementById('room') as HTMLInputElement;
|
||||
@@ -74,25 +63,9 @@ import { navigate } from "astro:transitions/client";
|
||||
const roomList = document.getElementById('room-list');
|
||||
const peerURLList = document.getElementById('peerURL-list');
|
||||
|
||||
// Load values from cookies
|
||||
function getCookie(name) {
|
||||
const value = `; ${document.cookie}`;
|
||||
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) {
|
||||
const d = new Date();
|
||||
d.setTime(d.getTime() + (days*24*60*60*1000));
|
||||
const expires = "expires="+ d.toUTCString();
|
||||
document.cookie = name + "=" + encodeURIComponent(value) + ";" + expires + ";path=/";
|
||||
}
|
||||
|
||||
const storedRooms = JSON.parse(getCookie('nestri-rooms') || '[]');
|
||||
const storedPeerURLs = JSON.parse(getCookie('nestri-peerURLs') || '[]');
|
||||
// Load values from localStorage
|
||||
const storedRooms = JSON.parse(localStorage.getItem('nestri-rooms') || '[]');
|
||||
const storedPeerURLs = JSON.parse(localStorage.getItem('nestri-peerURLs') || '[]');
|
||||
|
||||
if (roomList) {
|
||||
storedRooms.forEach(room => {
|
||||
@@ -122,17 +95,15 @@ import { navigate } from "astro:transitions/client";
|
||||
const room = roomInput.value;
|
||||
const peerURL = peerURLInput.value;
|
||||
|
||||
// Save values to cookies
|
||||
// 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);
|
||||
|
||||
setCookie('nestri-rooms', JSON.stringify(newRooms), 365);
|
||||
setCookie('nestri-peerURLs', JSON.stringify(newPeerURLs), 365);
|
||||
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>
|
||||
</body>
|
||||
</html>
|
||||
</script>
|
||||
|
||||
@@ -24,6 +24,22 @@ if (envs_map.size > 0) {
|
||||
|
||||
<script>
|
||||
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;
|
||||
let ENVS_MAP: Map<string, string | undefined> | null = null;
|
||||
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;
|
||||
}
|
||||