Compare commits

...

6 Commits

Author SHA1 Message Date
Vikeo
6d3bf32e4b Add the blobs 2024-06-03 15:18:52 +02:00
Vikeo
df3c30da31 fix 2024-05-27 11:01:43 +02:00
Vikeo
5fff18e079 check if ios 2024-05-27 11:01:25 +02:00
Vikeo
7203f0170a hotfix 2024-05-27 10:59:09 +02:00
Vikeo
63fbceafe2 fix null state 2024-05-27 10:58:42 +02:00
Vikeo
2ec9998a2a show and hide things based on ios, add button for installing PWA 2024-05-27 10:47:59 +02:00
10 changed files with 265 additions and 156 deletions

View File

@@ -1,12 +1,12 @@
index.html,1716462527631,3daeb4b4b2f195883f1e266f94c16156ee3c60a29c3eb8c44a8dcfdbb1fa0a03
manifest.webmanifest,1716462527631,10e89b44378da695cb672bf7d801a4ade909383751f1665416f561bbe1434e5d
manifest.json,1716462527513,91ce94afb71f33a477f5d8d48c3f98bd7de422279c74f17b6500eec72003ac1a
logo192.png,1716462527512,14ac21c3975e11951c1eb7793eec18e1cc3274bfe7cf7858636d547a9a4efc1c
registerSW.js,1716462527631,8db45a5ae8765ce12ec241d6c5bd5d30eb81dd9163b2685c5e1b867a0e487018
robots.txt,1716462527513,391d14b3c2f8c9143a27a28c7399585142228d4d1bdbe2c87ac946de411fa9a2
sw.js,1716462528602,b681e1b343578a0de67032920144d05430677997580429b7e2b749f6afff69ed
workbox-3e911b1d.js,1716462528602,666146b896084273226c83dca0b93f99accb195688330d6aa5c8c570bd48a4ac
assets/index-D9CdzROR.css,1716462527631,610c77754d47a35446b00c0a50488070c943f3a05e6d57658faefd943bc3fc46
favicon.ico,1716462527511,c3d2b7ac7f6263cca7ee26f91725eb32e7539bf0564f3b31a1bfc23cc88e9739
logo512.png,1716462527512,a9ebde1252bb76a5b474130ef07a7ed744448fde84221f715f3fec849eccbcd2
assets/index-DgCoW5us.js,1716462527631,06a6d92ff20d7f9e1f5e0c4d3ad8f931d7d0636f109b5e2dbbe28abd3707bb50
index.html,1716800495173,a60a0d61bc25aa1eb4446d628875d96224860fbd767a11682a6c1db79b9403e2
manifest.webmanifest,1716800495173,10e89b44378da695cb672bf7d801a4ade909383751f1665416f561bbe1434e5d
manifest.json,1716800495051,91ce94afb71f33a477f5d8d48c3f98bd7de422279c74f17b6500eec72003ac1a
registerSW.js,1716800495173,8db45a5ae8765ce12ec241d6c5bd5d30eb81dd9163b2685c5e1b867a0e487018
robots.txt,1716800495051,391d14b3c2f8c9143a27a28c7399585142228d4d1bdbe2c87ac946de411fa9a2
sw.js,1716800496019,609c6e27a6431ece2081013efab535a218046977d97b8600a6f58ba7589373c1
logo192.png,1716800495050,14ac21c3975e11951c1eb7793eec18e1cc3274bfe7cf7858636d547a9a4efc1c
workbox-3e911b1d.js,1716800496020,666146b896084273226c83dca0b93f99accb195688330d6aa5c8c570bd48a4ac
assets/index-B0S3b36T.css,1716800495173,1eb1cb3d1dacc339354071ee052cdacc07d1c831c61e08b082518436f3463d83
favicon.ico,1716800495050,c3d2b7ac7f6263cca7ee26f91725eb32e7539bf0564f3b31a1bfc23cc88e9739
logo512.png,1716800495051,a9ebde1252bb76a5b474130ef07a7ed744448fde84221f715f3fec849eccbcd2
assets/index-2MMQ0HyH.js,1716800495173,f14516d3e15bb8fa5079d40fb7c1a7e0974d336340936bbed066d792ee1021e5

View File

@@ -1,7 +1,7 @@
{
"name": "life-trinket",
"private": true,
"version": "0.9.95",
"version": "0.9.96",
"type": "commonjs",
"engines": {
"node": ">=20",

View File

@@ -2,6 +2,7 @@ import { twc } from 'react-twc';
import { useAnalytics } from '../../Hooks/useAnalytics';
import { useGlobalSettings } from '../../Hooks/useGlobalSettings';
import { PreStartMode } from '../../Types/Settings';
import { InstallPWAButton } from '../Misc/InstallPWAButton';
import { Separator } from '../Misc/Separator';
import { Paragraph } from '../Misc/TextComponents';
import { ToggleButton } from '../Misc/ToggleButton';
@@ -201,11 +202,10 @@ export const SettingsDialog = ({
is enabled.
</Description>
</SettingContainer>
{(!window.isIOS || window.isIPad) && (
<SettingContainer>
<ToggleContainer>
<label>
Fullscreen on start <span className="text-xs">(Android only)</span>
</label>
<label>Fullscreen on start</label>
<ToggleButton
checked={settings.goFullscreenOnStart}
onChange={() => {
@@ -220,6 +220,7 @@ export const SettingsDialog = ({
Will enter fullscreen mode when starting a game if this is enabled.
</Description>
</SettingContainer>
)}
<SettingContainer>
<ToggleContainer>
@@ -254,24 +255,48 @@ export const SettingsDialog = ({
</button>
</div>
{!isPWA && (
<>
{window.isIOS && (
<>
<Separator height="1px" />
<SettingContainer>
<ToggleContainer>
<Paragraph>
<b>Tip:</b> You can{' '}
<b>add this webapp to your home page on iOS</b> or{' '}
<b>install it on Android</b> to have it act just like a normal
app!
<b>Tip:</b> You can <b>add this webapp to your home page</b>{' '}
to have it act just like a normal app!
</Paragraph>
</ToggleContainer>
<Description className="mt-1">
If you do, this app will work offline and the toolbar will be
automatically hidden.
If you do, this web app will work offline and the toolbar will
be automatically hidden.
</Description>
</SettingContainer>
</>
)}
{!window.isIOS && (
<>
<Separator height="1px" />
<SettingContainer>
<ToggleContainer>
<Paragraph>
<b>Tip:</b> You can <b>install this page as a PWA</b> to
have it act just like a normal app!
</Paragraph>
</ToggleContainer>
<Description className="mt-1">
If you do, this web app will work offline and the toolbar will
be automatically hidden. PWA stands for Progressive Web
Application
</Description>
</SettingContainer>
<div className="flex w-full justify-center">
<InstallPWAButton />
</div>
</>
)}
</>
)}
<Separator height="1px" />
</Dialog>
);

View File

@@ -0,0 +1,45 @@
import { useEffect, useRef, useState } from 'react';
import { BeforeInstallPromptEvent } from '../../global';
import { useAnalytics } from '../../Hooks/useAnalytics';
export const InstallPWAButton = () => {
const supportsPWARef = useRef<boolean>(false);
const [promptInstall, setPromptInstall] =
useState<BeforeInstallPromptEvent | null>(null);
const analytics = useAnalytics();
const handler = (e: BeforeInstallPromptEvent) => {
e.preventDefault();
supportsPWARef.current = true;
setPromptInstall(e);
};
useEffect(() => {
window.addEventListener('beforeinstallprompt', handler);
return () => window.removeEventListener('transitionend', handler);
}, []);
if (!supportsPWARef.current) {
return null;
}
return (
<button
className="mt-1 mb-1 bg-primary-main px-3 py-1 rounded-md duration-200 ease-in-out shadow-[1px_2px_4px_0px_rgba(0,0,0,0.3)] hover:bg-primary-dark font-bold"
aria-label="Install app"
title="Install app"
onClick={(e) => {
e.preventDefault();
if (!promptInstall) {
return;
}
analytics.trackEvent('install_pwa_prompt_shown');
promptInstall.prompt();
}}
>
Install as a PWA
</button>
);
};

View File

@@ -347,6 +347,7 @@ const PlayerMenu = ({
>
<Exit size={iconSize} style={{ rotate: '180deg' }} />
</button>
{(!window.isIOS || window.isIPad) && (
<div
data-fullscreen={document.fullscreenElement ? true : false}
className="flex
@@ -364,13 +365,17 @@ const PlayerMenu = ({
/>
}
checkedIcon={
<FullscreenOn size={iconSize} className="text-primary-main" />
<FullscreenOn
size={iconSize}
className="text-primary-main"
/>
}
onChange={toggleFullscreen}
aria-checked={document.fullscreenElement ? true : false}
aria-label="Fullscreen"
/>
</div>
)}
<button
data-wake-lock-active={settings.keepAwake}

View File

@@ -36,9 +36,9 @@ const standardSettings: Pick<
orientation: Orientation.Landscape,
};
const MainWrapper = twc.div`h-fit w-full pb-24 overflow-hidden items-center flex flex-col min-[349px]:pb-10`;
const MainWrapper = twc.div`h-fit w-full pb-24 overflow-hidden items-center flex flex-col min-[349px]:pb-10 z-10`;
const StartButtonFooter = twc.div`w-full max-w-[548px] fixed bottom-4 z-1 items-center flex flex-row flex-wrap px-4 z-10 gap-4`;
const StartButtonFooter = twc.div`w-full max-w-[548px] fixed bottom-4 z-10 items-center flex flex-row flex-wrap px-4 gap-4`;
const SliderWrapper = twc.div`mx-8 relative`;
@@ -237,14 +237,14 @@ const Start = () => {
<>
<InfoDialog dialogRef={infoDialogRef} />
{settings.showAnimations && (
<>
<div className="blob-container">
<div className="spotlight1" />
<div className="spotlight2" />
</>
</div>
)}
<SettingsDialog dialogRef={settingsDialogRef} />
<div className="flex justify-center items-center w-screen">
<div className="flex justify-center items-center w-screen z-10">
<MainWrapper>
<Info
className="size-8 absolute top-7 left-4 text-primary-main"
@@ -387,7 +387,7 @@ const Start = () => {
}}
/>
</div>
{!isPWA && (
{!isPWA && window.isIOS && (
<p className="text-center text-xs text-text-primary w-11/12 mt-4">
If you're on iOS, this page works better if you{' '}
<strong>hide the toolbar</strong> or{' '}

21
src/global.d.ts vendored Normal file
View File

@@ -0,0 +1,21 @@
export {};
export interface BeforeInstallPromptEvent extends Event {
readonly platforms: string[];
readonly userChoice: Promise<{
outcome: 'accepted' | 'dismissed';
platform: string;
}>;
prompt(): Promise<void>;
}
declare global {
interface Window {
isIOS: boolean;
isIPad: boolean;
}
interface WindowEventMap {
beforeinstallprompt: BeforeInstallPromptEvent;
transitionend: BeforeInstallPromptEvent;
}
}

View File

@@ -81,86 +81,6 @@ code {
}
}
@keyframes background-orb {
0% {
bottom: 10%;
}
50% {
bottom: 90%;
}
100% {
bottom: 10%;
}
}
@keyframes move-right-left {
0% {
rotate: 0deg;
right: 10%;
}
25% {
right: 70%;
}
50% {
rotate: 360deg;
right: 10%;
}
75% {
right: 90%;
}
100% {
rotate: 0deg;
right: 10%;
}
}
.spotlight1 {
background: theme('colors.background.default');
position: fixed;
height: 10vmax;
width: 30vmax;
border-radius: 100%;
transform: translate(50%, 50%);
animation-duration: 30s, 60s;
animation-name: background-orb, move-right-left;
animation-iteration-count: infinite, infinite;
animation-direction: alternate, alternate;
animation-timing-function: ease-in-out;
animation-delay: -15s, -15s;
opacity: 0.8;
mix-blend-mode: screen;
filter: blur(10vmax);
}
.spotlight2 {
background: theme('colors.background.default');
position: fixed;
height: 30vmax;
width: 10vmax;
border-radius: 100%;
transform: translate(50%, 50%);
animation-duration: 60s, 120s;
animation-name: background-orb, move-right-left;
animation-iteration-count: infinite, infinite;
animation-direction: reverse, reverse;
animation-timing-function: ease-in-out;
opacity: 0.8;
mix-blend-mode: screen;
filter: blur(10vmax);
}
input[type='range'] {
-webkit-appearance: none;
transition: background 0ms ease-in;
@@ -229,3 +149,92 @@ input[type='range']::-ms-thumb {
cursor: pointer;
margin-top: -3px;
}
.blob-container {
margin: auto;
position: absolute;
display: flex;
align-items: center;
width: 100vw;
height: 100vh;
filter: blur(10vmax) contrast(10);
z-index: 9;
background: theme('colors.background.default');
mix-blend-mode: screen;
opacity: 30%;
}
@keyframes background-orb {
0% {
bottom: 10%;
}
50% {
bottom: 70%;
}
100% {
bottom: 10%;
}
}
@keyframes move-right-left {
0% {
rotate: 0deg;
right: 10%;
}
25% {
right: 20%;
}
50% {
rotate: 360deg;
right: 10%;
}
75% {
right: 30%;
}
100% {
rotate: 0deg;
right: 10%;
}
}
.spotlight1 {
background: theme('colors.background.spotlight');
position: fixed;
height: 20vmax;
width: 70vmax;
border-radius: 100%;
transform: translate(50%, 50%);
animation-duration: 15s, 50s;
animation-name: background-orb, move-right-left;
animation-iteration-count: infinite, infinite;
animation-direction: alternate, alternate;
animation-timing-function: ease-in-out;
animation-delay: -15s, -15s;
/* filter: blur(5vmax); */
}
.spotlight2 {
background: theme('colors.background.spotlight');
position: fixed;
height: 70vmax;
width: 20vmax;
border-radius: 100%;
transform: translate(50%, 50%);
animation-duration: 30s, 100s;
animation-name: background-orb, move-right-left;
animation-iteration-count: infinite, infinite;
animation-direction: reverse, reverse;
animation-timing-function: ease-in-out;
/* filter: blur(5vmax); */
}

View File

@@ -3,6 +3,10 @@ import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './index.css';
window.isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
window.isIPad = /iPad/.test(navigator.userAgent);
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);

View File

@@ -13,7 +13,7 @@ export const baseColors = {
},
background: {
default: '#2E3041', // Orig: #35374B
spotlight: '#777BA7',
spotlight: 'hsl(110, 80.4%, 32.1%)',
backdrop: 'rgba(0, 0, 0, 0.3)',
settings: 'rgba(0, 0, 0, 0.8)',
},