Mobile friendly and styled planner

This commit is contained in:
hfcRed 2026-03-18 03:26:58 +01:00
parent 858fcf750d
commit 546328ec43
3 changed files with 182 additions and 46 deletions

View File

@ -1,8 +1,45 @@
.topSection {
.topWrapper {
position: fixed;
z-index: 10;
top: 0;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
max-width: 100%;
}
.topWrapperCollapsed {
transform: translateX(-50%) translateY(-100%);
& .topSection {
visibility: hidden;
}
}
.topToggle {
position: absolute;
bottom: 0;
transform: translateY(100%);
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
width: var(--field-size);
padding: var(--s-0-5) 0;
border: var(--border-style);
border-top: none;
border-radius: 0 0 var(--radius-selector) var(--radius-selector);
background-color: var(--color-bg);
cursor: pointer;
&:hover {
background-color: var(--color-bg-high);
}
}
.topSection {
display: flex;
align-items: center;
padding: var(--s-2);
@ -11,7 +48,6 @@
border-radius: 0 0 var(--radius-box) var(--radius-box);
background-color: var(--color-bg);
gap: var(--s-2);
transform: translate(-50%, 0);
max-width: 100%;
overflow: auto;
animation: scrolling forwards;
@ -27,19 +63,17 @@
}
}
.outlineToggle {
position: fixed;
z-index: 10;
top: 10%;
left: 5px;
}
.outlineToggleButton {
background-color: var(--color-bg-high);
color: var(--color-text);
font-size: var(--font-xs);
padding: var(--s-2);
width: 140px;
width: 100%;
border-radius: 0;
border-bottom: var(--border-style);
transform: translateY(0);
position: sticky;
top: 0;
}
.outlineToggleButtonOutlined {
@ -47,12 +81,46 @@
color: var(--color-text-inverse);
}
.weaponsSection {
.weaponsWrapper {
position: fixed;
z-index: 10;
top: 15%;
top: 15vh;
left: 0;
}
.weaponsWrapperCollapsed {
transform: translateX(-100%);
& .weaponsSection {
visibility: hidden;
}
}
.weaponsToggle {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%) translateX(100%);
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
height: var(--field-size);
padding: 0 var(--s-0-5);
border: var(--border-style);
border-left: none;
border-radius: 0 var(--radius-selector) var(--radius-selector) 0;
background-color: var(--color-bg);
cursor: pointer;
&:hover {
background-color: var(--color-bg-high);
}
}
.weaponsSection {
width: 150px;
max-height: 85vh;
max-height: 70vh;
border: var(--border-style);
border-left: transparent;
border-radius: 0 var(--radius-box) var(--radius-box) 0;
@ -85,7 +153,7 @@
.stylePanel {
position: fixed;
z-index: 10;
top: calc(10% - 8px);
top: 15vh;
right: 0;
}

View File

@ -22,7 +22,13 @@ import {
Tldraw,
} from "@tldraw/tldraw";
import clsx from "clsx";
import { LogOut } from "lucide-react";
import {
ChevronDown,
ChevronLeft,
ChevronRight,
ChevronUp,
LogOut,
} from "lucide-react";
import * as React from "react";
import { useTranslation } from "react-i18next";
import { useTheme } from "~/features/theme/core/provider";
@ -55,11 +61,15 @@ const BACKGROUND_WIDTH = 1127;
const BACKGROUND_HEIGHT = 634;
export default function Planner() {
const { i18n } = useTranslation();
const { t, i18n } = useTranslation(["common"]);
const { htmlThemeClass } = useTheme();
const isWide = i18n.language === "fr";
const [editor, setEditor] = React.useState<Editor | null>(null);
const [imgOutlined, setImgOutlined] = React.useState(false);
const [topCollapsed, setTopCollapsed] = React.useState(false);
const [weaponsCollapsed, setWeaponsCollapsed] = React.useState(false);
const [activeDragItem, setActiveDragItem] = React.useState<{
src: string;
previewPath: string;
@ -246,9 +256,62 @@ export default function Planner() {
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
>
<StageBackgroundSelector onAddBackground={handleAddBackgroundImage} />
<OutlineToggle outlined={imgOutlined} setImgOutlined={setImgOutlined} />
<WeaponImageSelector />
<div
className={clsx(
styles.topWrapper,
topCollapsed && styles.topWrapperCollapsed,
)}
>
<StageBackgroundSelector onAddBackground={handleAddBackgroundImage} />
<button
type="button"
className={styles.topToggle}
onClick={() => setTopCollapsed(!topCollapsed)}
aria-label={
topCollapsed
? t("common:actions.showMore")
: t("common:actions.hide")
}
>
{topCollapsed ? <ChevronDown size={16} /> : <ChevronUp size={16} />}
</button>
</div>
<div
className={clsx(
styles.weaponsWrapper,
weaponsCollapsed && styles.weaponsWrapperCollapsed,
)}
>
<div
className={clsx(
styles.weaponsSection,
"scrollbar",
isWide && styles.weaponsSectionWide,
)}
>
<OutlineToggle
outlined={imgOutlined}
setImgOutlined={setImgOutlined}
/>
<WeaponImageSelector />
</div>
<button
type="button"
className={styles.weaponsToggle}
onClick={() => setWeaponsCollapsed(!weaponsCollapsed)}
aria-label={
weaponsCollapsed
? t("common:actions.showMore")
: t("common:actions.hide")
}
>
{weaponsCollapsed ? (
<ChevronRight size={16} />
) : (
<ChevronLeft size={16} />
)}
</button>
</div>
<div style={{ position: "fixed", inset: 0 }}>
<Tldraw onMount={handleMount} components={tldrawComponents} />
</div>
@ -291,20 +354,16 @@ function OutlineToggle({
};
return (
<div className={styles.outlineToggle}>
<SendouButton
variant="minimal"
onPress={handleClick}
className={clsx(
styles.outlineToggleButton,
outlined && styles.outlineToggleButtonOutlined,
)}
>
{outlined
? t("common:actions.outlined")
: t("common:actions.noOutline")}
</SendouButton>
</div>
<SendouButton
variant="minimal"
onPress={handleClick}
className={clsx(
styles.outlineToggleButton,
outlined && styles.outlineToggleButtonOutlined,
)}
>
{outlined ? t("common:actions.outlined") : t("common:actions.noOutline")}
</SendouButton>
);
}
@ -353,18 +412,10 @@ function DraggableWeaponButton({
}
function WeaponImageSelector() {
const { t, i18n } = useTranslation(["weapons", "common", "game-misc"]);
const isWide = i18n.language === "fr";
const { t } = useTranslation(["weapons", "common", "game-misc"]);
return (
<div
className={clsx(
styles.weaponsSection,
"scrollbar",
isWide && styles.weaponsSectionWide,
)}
>
<>
{weaponCategories.map((category) => {
return (
<details key={category.name}>
@ -467,7 +518,7 @@ function WeaponImageSelector() {
})}
</div>
</details>
</div>
</>
);
}

View File

@ -62,8 +62,25 @@ body:has(.planner) header {
display: none;
}
.tl-canvas {
background-color: var(--color-bg);
.tl-theme__dark.tl-theme__dark,
.tl-theme__light.tl-theme__light {
--color-panel: var(--color-bg);
--color-divider: var(--color-border);
--color-selected: var(--color-text-accent);
--color-selected-contrast: var(--color-text-inverse);
--color-hint: var(--color-bg-high);
--color-muted-2: var(--color-bg-high);
--color-background: var(--color-bg);
}
.tlui-style-panel,
.tlui-toolbar__tools,
.tlui-popover__content {
border: var(--border-style);
}
.tlui-style-panel {
margin-top: 0 !important;
}
.tlui-toolbar-container.tlui-toolbar__tools {