More work on responsive design for small screens

This commit is contained in:
Davide Passoni
2024-07-02 17:36:53 +02:00
parent 00e2da2aab
commit 96b3e2f115
16 changed files with 225 additions and 155 deletions

View File

@@ -106,10 +106,7 @@ export function OlDropdown(props: {
type="button"
>
{props.leftIcon && (
<FontAwesomeIcon
icon={props.leftIcon}
className={`mr-3`}
/>
<FontAwesomeIcon icon={props.leftIcon} className={`mr-3`} />
)}
<span className="overflow-hidden text-ellipsis text-nowrap">
{props.label}
@@ -138,7 +135,7 @@ export function OlDropdown(props: {
ref={contentRef}
data-open={open}
className={`
absolute z-ui-2 w-full divide-y divide-gray-100 overflow-y-scroll
absolute z-ui-4 w-full divide-y divide-gray-100 overflow-y-scroll
rounded-lg bg-white p-2 shadow
dark:bg-gray-700
data-[open='false']:hidden

View File

@@ -38,7 +38,7 @@ export function LoginModal(props: {
<Modal
className={`
inline-flex h-[75%] max-h-[530px] w-[80%] max-w-[1100px] overflow-y-auto
scroll-smooth bg-white
scroll-smooth bg-white z-ui-5
dark:bg-olympus-800
max-md:h-full max-md:max-h-full max-md:w-full max-md:rounded-none
max-md:border-none
@@ -111,9 +111,7 @@ export function LoginModal(props: {
></img>
</span>
<div
className={`
flex flex-col items-start gap-1
`}
className={`flex flex-col items-start gap-1`}
>
<h1
className={`
@@ -143,10 +141,7 @@ export function LoginModal(props: {
{props.commandMode === null ? (
<>
<div
className={`
flex flex-col items-start
gap-2
`}
className={`flex flex-col items-start gap-2`}
>
<label
className={`
@@ -157,7 +152,7 @@ export function LoginModal(props: {
Password{" "}
</label>
<input
type="text"
type="password"
onChange={(ev) =>
setPassword(ev.currentTarget.value)
}

View File

@@ -14,10 +14,11 @@ export function Menu(props: {
<div
data-open={props.open}
className={`
absolute left-16 top-[62px] w-[430px] z-ui-0 h-screen overflow-y-auto
bg-gray-200 backdrop-blur-lg backdrop-grayscale transition-transform
absolute left-16 right-0 top-[60px] bg-gray-200 backdrop-grayscale
z-ui-3 h-screen overflow-y-auto backdrop-blur-lg transition-transform
dark:bg-olympus-800/90
data-[open='false']:-translate-x-full
sm:w-[400px]
`}
tabIndex={-1}
>

View File

@@ -0,0 +1,39 @@
import React, { useState } from "react";
import { FaHandPointer } from "react-icons/fa6";
import { IDLE, SPAWN_UNIT } from "../../constants/constants";
export function MapStatePanel(props: {}) {
const [mapState, setMapState] = useState(IDLE);
document.addEventListener("mapStateChanged", (ev) => {
setMapState((ev as CustomEvent).detail);
});
return (
<div
className={`
absolute bottom-6 right-[10px] w-[288px] z-ui-5 flex items-center
justify-between rounded-lg bg-gray-200 p-3 text-sm backdrop-blur-lg
backdrop-grayscale
dark:bg-olympus-800/90 dark:text-gray-200
`}
>
<div className={`flex w-full items-center gap-2 font-semibold`}>
{mapState === IDLE && "IDLE"}
{mapState === SPAWN_UNIT && (
<div className={`flex w-full items-center`}>
<FaHandPointer className="mr-2 text-sm text-white" />
<div
className={`
w-full animate-pulse border-l-[1px] px-2 text-center
dark:text-white
`}
>
Click on the map to spawn
</div>
</div>
)}
</div>
</div>
);
}

View File

@@ -1,6 +1,8 @@
import React, { useState, useEffect } from "react";
import { zeroAppend } from "../../other/utils";
import { DateAndTime } from "../../interfaces";
import { getApp } from "../../olympusapp";
import { FaChevronDown, FaChevronUp } from "react-icons/fa6";
export function MiniMapPanel(props: {}) {
var [frameRate, setFrameRate] = useState(0);
@@ -14,14 +16,16 @@ export function MiniMapPanel(props: {}) {
var [connected, setConnected] = useState(false);
var [paused, setPaused] = useState(false);
var [showMissionTime, setShowMissionTime] = useState(false);
var [showMinimap, setShowMinimap] = useState(false);
document.addEventListener("serverStatusUpdated", (ev) => {
setFrameRate(ev.detail.frameRate);
setLoad(ev.detail.load);
setElapsedTime(ev.detail.elapsedTime);
setMissionTime(ev.detail.missionTime);
setConnected(ev.detail.connected);
setPaused(ev.detail.paused);
const detail = (ev as CustomEvent).detail;
setFrameRate(detail.frameRate);
setLoad(detail.load);
setElapsedTime(detail.elapsedTime);
setMissionTime(detail.missionTime);
setConnected(detail.connected);
setPaused(detail.paused);
});
// A bit of a hack to set the rounded borders to the minimap
@@ -32,6 +36,10 @@ export function MiniMapPanel(props: {}) {
}
});
document.addEventListener("mapOptionsChanged", (event) => {
setShowMinimap(getApp().getMap().getOptions().showMinimap);
});
// Compute the time string depending on mission or elapsed time
let hours = 0;
let minutes = 0;
@@ -63,62 +71,57 @@ export function MiniMapPanel(props: {}) {
<div
onClick={() => setShowMissionTime(!showMissionTime)}
className={`
absolute right-[10px] top-[233px] w-[288px] z-ui-0 flex items-center
justify-between rounded-b-lg bg-gray-200 p-3 text-sm backdrop-blur-lg
backdrop-grayscale
absolute right-[10px]
${showMinimap ? `top-[232px]` : `top-[70px]`}
w-[288px] z-ui-0 flex items-center justify-between
${showMinimap ? `rounded-b-lg` : `rounded-lg`}
bg-gray-200 p-3 text-sm backdrop-blur-lg backdrop-grayscale
dark:bg-olympus-800/90 dark:text-gray-200
`}
>
{!connected ? (
<div
className={`
flex animate-pulse items-center gap-2 font-semibold
`}
>
<div
className={`relative h-4 w-4 rounded-full bg-[#F05252]`}
></div>
<div className={`flex animate-pulse items-center gap-2 font-semibold`}>
<div className={`relative h-4 w-4 rounded-full bg-[#F05252]`}></div>
Server disconnected
</div>
) : paused ? (
<div
className={`
flex animate-pulse items-center gap-2 font-semibold
`}
>
<div
className={`relative h-4 w-4 rounded-full bg-[#FF9900]`}
></div>
<div className={`flex animate-pulse items-center gap-2 font-semibold`}>
<div className={`relative h-4 w-4 rounded-full bg-[#FF9900]`}></div>
Server paused
</div>
) : (
<>
<div className="font-semibold">
FPS:{" "}
<span
style={{ color: frameRateColor }}
className={`font-semibold`}
>
<span style={{ color: frameRateColor }} className={`font-semibold`}>
{frameRate}
</span>{" "}
</div>
<div className="font-semibold">
Load:{" "}
<span
style={{ color: loadColor }}
className={`font-semibold`}
>
<span style={{ color: loadColor }} className={`font-semibold`}>
{load}
</span>{" "}
</div>
<div className="font-semibold">
{showMissionTime ? "MT" : "ET"}: {timeString}{" "}
</div>
<div
className={`relative h-4 w-4 rounded-full bg-[#8BFF63]`}
></div>
<div className={`relative h-4 w-4 rounded-full bg-[#8BFF63]`}></div>
</>
)}
{showMinimap ? (
<FaChevronUp
onClick={() => {
getApp().getMap().setOption("showMinimap", false);
}}
></FaChevronUp>
) : (
<FaChevronDown
onClick={() => {
getApp().getMap().setOption("showMinimap", true);
}}
></FaChevronDown>
)}
</div>
);
}

View File

@@ -196,6 +196,33 @@ export function Options(props: {
G
</kbd>
</div>
<div
className={`
group flex flex-row rounded-md justify-content cursor-pointer gap-4
p-2
dark:hover:bg-olympus-400
`}
onClick={() => {
getApp()
.getMap()
.setOption("showMinimap", !props.options.showMinimap);
}}
>
<OlCheckbox
checked={props.options.showMinimap}
onChange={() => {}}
></OlCheckbox>
<span>Show minimap</span>
<kbd
className={`
ml-auto rounded-lg border border-gray-200 bg-gray-100 px-2 py-1.5
text-xs font-semibold text-gray-800
dark:border-gray-500 dark:bg-gray-600 dark:text-gray-100
`}
>
?
</kbd>
</div>
{/*
<hr className="w-auto m-2 my-1 bg-gray-700 border-[1px] dark:border-olympus-500"></hr>

View File

@@ -21,16 +21,20 @@ export function SideBar() {
{(events) => (
<nav
className={`
flex flex-col z-ui-1 h-full bg-gray-300
flex flex-col z-ui-4 h-full bg-gray-300
dark:bg-olympus-900
`}
>
<div className={`
w-16 flex-1 flex-wrap items-center justify-center p-4
`}>
<div className={`
<div
className={`
w-16 flex-1 flex-wrap items-center justify-center p-4
`}
>
<div
className={`
flex flex-col items-center justify-center gap-2.5
`}>
`}
>
<OlStateButton
onClick={events.toggleMainMenuVisible}
checked={appState.mainMenuVisible}
@@ -64,9 +68,11 @@ export function SideBar() {
</div>
</div>
<div className="flex w-16 flex-wrap content-end justify-center p-4">
<div className={`
<div
className={`
flex flex-col items-center justify-center gap-2.5
`}>
`}
>
<OlStateButton
onClick={() =>
window.open("https://github.com/Pax1601/DCSOlympus/wiki")

View File

@@ -35,8 +35,9 @@ import {
import { Coalition } from "../../types/types";
import { ftToM, knotsToMs, mToFt, msToKnots } from "../../other/utils";
export function UnitControlMenu() {
var [open, setOpen] = useState(false);
export function UnitControlMenu(props: {
open: boolean
}) {
var [selectedUnits, setSelectedUnits] = useState([] as Unit[]);
var [selectedUnitsData, setSelectedUnitsData] = useState({
@@ -94,7 +95,6 @@ export function UnitControlMenu() {
/* When a unit is selected, open the menu */
document.addEventListener("unitsSelection", (ev: CustomEventInit) => {
setOpen(true);
setSelectedUnits(ev.detail as Unit[]);
updateData();
@@ -108,7 +108,6 @@ export function UnitControlMenu() {
/* When all units are deselected clean the view */
document.addEventListener("clearSelection", () => {
setOpen(false);
setSelectedUnits([]);
});
@@ -185,7 +184,7 @@ export function UnitControlMenu() {
getApp()?.getUnitsManager()?.getSelectedUnitsCategories() ?? [];
return (
<Menu open={open} title="Units selected (x)" onClose={() => {}}>
<Menu open={props.open} title="Units selected (x)" onClose={() => {}}>
{/* Units list */}
<div
className={`
@@ -240,9 +239,11 @@ export function UnitControlMenu() {
return ["Aircraft", "Helicopter"].includes(category);
}) && (
<div>
<div className={`
flex flex-row content-center items-center justify-between
`}>
<div
className={`
flex flex-row content-center items-center justify-between
`}
>
<div className="flex flex-col">
<span
className={`
@@ -313,9 +314,11 @@ export function UnitControlMenu() {
}
{/* Airspeed selector */}
<div>
<div className={`
flex flex-row content-center items-center justify-between
`}>
<div
className={`
flex flex-row content-center items-center justify-between
`}
>
<div className="flex flex-col">
<span
className={`
@@ -417,9 +420,7 @@ export function UnitControlMenu() {
}) && (
<>
{" "}
<div
className={`flex flex-col gap-2`}
>
<div className={`flex flex-col gap-2`}>
<span
className={`
font-normal
@@ -573,9 +574,7 @@ export function UnitControlMenu() {
}) && (
<>
{" "}
<div
className={`flex flex-col gap-2`}
>
<div className={`flex flex-col gap-2`}>
<span
className={`
font-normal

View File

@@ -40,7 +40,7 @@ export function UnitMouseControlBar(props: {}) {
/* Deselect the context action when exiting state */
document.addEventListener("mapStateChanged", (ev) => {
setOpen(ev.detail === CONTEXT_ACTION);
setOpen((ev as CustomEvent).detail === CONTEXT_ACTION);
});
/* Update the current values of the shown data */
@@ -65,8 +65,8 @@ export function UnitMouseControlBar(props: {}) {
<>
<div
className={`
absolute left-[50%] top-20 flex translate-x-[-50%] gap-2
rounded-md bg-gray-200 p-2 z-ui-2
absolute left-[50%] top-16 flex translate-x-[calc(-50%+2rem)]
gap-2 rounded-md bg-gray-200 p-2 z-ui-2
dark:bg-olympus-900
`}
>
@@ -84,11 +84,9 @@ export function UnitMouseControlBar(props: {}) {
} else {
if (activeContextAction != contextAction) {
setActiveContextAction(contextAction);
getApp()
.getMap()
.setState(CONTEXT_ACTION, {
contextAction: contextAction,
});
getApp().getMap().setState(CONTEXT_ACTION, {
contextAction: contextAction,
});
} else {
setActiveContextAction(null);
getApp()
@@ -105,16 +103,21 @@ export function UnitMouseControlBar(props: {}) {
{activeContextAction && (
<div
className={`
absolute left-[50%] top-36 flex translate-x-[-50%] items-center
gap-2 rounded-md bg-gray-200 p-4 z-ui-1
absolute left-[50%] top-32 flex translate-x-[calc(-50%+2rem)]
items-center gap-2 rounded-md bg-gray-200 p-4 z-ui-1
min-w-[300px]
dark:bg-olympus-800
`}
>
<FaInfoCircle className="mr-2 text-sm text-blue-500" />
<FaInfoCircle className={`
mr-2 hidden min-w-8 text-sm text-blue-500
md:block
`} />
<div
className={`
border-l-[1px] px-5
px-2
dark:text-gray-400
md:border-l-[1px] md:px-5
`}
>
{activeContextAction.getDescription()}

View File

@@ -24,6 +24,7 @@ import { LoginModal } from "./modals/login";
import { sha256 } from "js-sha256";
import { MiniMapPanel } from "./panels/minimappanel";
import { UnitMouseControlBar } from "./panels/unitmousecontrolbar";
import { MapStatePanel } from "./panels/mapstatepanel";
export type OlympusState = {
mainMenuVisible: boolean;
@@ -188,9 +189,11 @@ export function UI() {
<div className="flex h-full">
{loginModalVisible && (
<>
<div className={`
fixed left-0 top-0 h-full w-full z-ui-3 bg-[#111111]/95
`}></div>
<div
className={`
fixed left-0 top-0 h-full w-full z-ui-5 bg-[#111111]/95
`}
></div>
<LoginModal
onLogin={(password) => {
checkPassword(password);
@@ -222,9 +225,10 @@ export function UI() {
options={mapOptions}
/>
<MiniMapPanel />
<UnitControlMenu />
<UnitControlMenu open={unitControlMenuVisible} />
<div id="map-container" className="h-full w-screen" />
<UnitMouseControlBar />
<MapStatePanel />
</div>
</div>
</EventsProvider>