feat(studio): ���������� UI + fullscreen + desktop-guard #46
@ -1,8 +1,10 @@
|
|||||||
/* === Hierarchy Panel === */
|
/* === Hierarchy Panel === */
|
||||||
|
/* Компактные строки (как Roblox Explorer): меньше вертикальных отступов —
|
||||||
|
больше объектов влезает без скролла. */
|
||||||
.hierarchy {
|
.hierarchy {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 6px 0;
|
padding: 4px 0;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -13,13 +15,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rootLine {
|
.rootLine {
|
||||||
padding: 6px 8px;
|
padding: 3px 8px;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
font-size: 13px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.systemItem {
|
.systemItem {
|
||||||
padding: 4px 8px 4px 28px;
|
padding: 2px 8px 2px 26px;
|
||||||
color: var(--text-dim);
|
color: var(--text-dim);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
@ -28,11 +30,11 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
padding: 6px 8px;
|
padding: 3px 8px;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin-top: 6px;
|
margin-top: 3px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,8 +74,8 @@
|
|||||||
.item {
|
.item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 7px;
|
||||||
padding: 4px 8px;
|
padding: 2px 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
|
|||||||
@ -73,6 +73,9 @@ const GLYPHS = {
|
|||||||
'arrow-down': () => (<><path d="M12 5v14" {...S}/><path d="M6 13l6 6 6-6" {...S}/></>),
|
'arrow-down': () => (<><path d="M12 5v14" {...S}/><path d="M6 13l6 6 6-6" {...S}/></>),
|
||||||
'arrow-left': () => (<><path d="M19 12H5" {...S}/><path d="M11 6l-6 6 6 6" {...S}/></>),
|
'arrow-left': () => (<><path d="M19 12H5" {...S}/><path d="M11 6l-6 6 6 6" {...S}/></>),
|
||||||
'arrow-right': () => (<><path d="M5 12h14" {...S}/><path d="M13 6l6 6-6 6" {...S}/></>),
|
'arrow-right': () => (<><path d="M5 12h14" {...S}/><path d="M13 6l6 6-6 6" {...S}/></>),
|
||||||
|
// Полноэкранный режим: 4 уголка наружу / внутрь.
|
||||||
|
'fullscreen': () => (<><path d="M4 9V4h5" {...S}/><path d="M20 9V4h-5" {...S}/><path d="M4 15v5h5" {...S}/><path d="M20 15v5h-5" {...S}/></>),
|
||||||
|
'fullscreen-exit': () => (<><path d="M9 4v5H4" {...S}/><path d="M15 4v5h5" {...S}/><path d="M9 20v-5H4" {...S}/><path d="M15 20v-5h5" {...S}/></>),
|
||||||
refresh: () => (<><path d="M20 11a8 8 0 0 0-14-4.5L4 9" {...S}/><path d="M4 4v5h5" {...S}/><path d="M4 13a8 8 0 0 0 14 4.5L20 15" {...S}/><path d="M20 20v-5h-5" {...S}/></>),
|
refresh: () => (<><path d="M20 11a8 8 0 0 0-14-4.5L4 9" {...S}/><path d="M4 4v5h5" {...S}/><path d="M4 13a8 8 0 0 0 14 4.5L20 15" {...S}/><path d="M20 20v-5h-5" {...S}/></>),
|
||||||
cycle: () => (<><path d="M20 11a8 8 0 0 0-14-4.5L4 9" {...S}/><path d="M4 4v5h5" {...S}/><path d="M4 13a8 8 0 0 0 14 4.5L20 15" {...S}/><path d="M20 20v-5h-5" {...S}/></>),
|
cycle: () => (<><path d="M20 11a8 8 0 0 0-14-4.5L4 9" {...S}/><path d="M4 4v5h5" {...S}/><path d="M4 13a8 8 0 0 0 14 4.5L20 15" {...S}/><path d="M20 20v-5h-5" {...S}/></>),
|
||||||
flag: () => (<><path d="M6 21V4" {...S}/><path d="M6 4h11l-2.5 4L17 12H6" {...S}/></>),
|
flag: () => (<><path d="M6 21V4" {...S}/><path d="M6 4h11l-2.5 4L17 12H6" {...S}/></>),
|
||||||
|
|||||||
@ -46,6 +46,11 @@ import cl from './KubikonEditor.module.css';
|
|||||||
import Icon from './Icon';
|
import Icon from './Icon';
|
||||||
import ConfirmModal from './ConfirmModal';
|
import ConfirmModal from './ConfirmModal';
|
||||||
|
|
||||||
|
// В десктоп-приложении (Electron-обёртка, см. rublox-desktop) окно и так на
|
||||||
|
// весь экран без браузерной панели — fullscreen НЕ нужен. preload выставляет
|
||||||
|
// window.__RUBLOX_DESKTOP__. Глушим авто-fullscreen, чтобы не дёргать окно.
|
||||||
|
const IS_DESKTOP_APP = typeof window !== 'undefined' && !!window.__RUBLOX_DESKTOP__;
|
||||||
|
|
||||||
const AUTOSAVE_DEBOUNCE_MS = 10000; // 10 секунд тишины → авто-сохранение
|
const AUTOSAVE_DEBOUNCE_MS = 10000; // 10 секунд тишины → авто-сохранение
|
||||||
|
|
||||||
// Шаблон глобального скрипта.
|
// Шаблон глобального скрипта.
|
||||||
@ -469,6 +474,98 @@ const KubikonEditor = () => {
|
|||||||
|
|
||||||
const canvasRef = useRef(null);
|
const canvasRef = useRef(null);
|
||||||
const sceneRef = useRef(null);
|
const sceneRef = useRef(null);
|
||||||
|
// === Fullscreen редактора ===
|
||||||
|
// Верхняя панель браузера съедает ~20% экрана. Браузер НЕ даёт включить
|
||||||
|
// fullscreen автоматически при загрузке (нужен user gesture), поэтому:
|
||||||
|
// 1) кнопка в шапке;
|
||||||
|
// 2) автоматический вход при ПЕРВОМ клике пользователя по редактору.
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
const fsAutoTriedRef = useRef(false); // авто-вход пробуем только 1 раз
|
||||||
|
const requestEditorFullscreen = React.useCallback(() => {
|
||||||
|
try {
|
||||||
|
const root = document.documentElement;
|
||||||
|
const req = root.requestFullscreen
|
||||||
|
|| root.webkitRequestFullscreen
|
||||||
|
|| root.mozRequestFullScreen
|
||||||
|
|| root.msRequestFullscreen;
|
||||||
|
if (req && !document.fullscreenElement) req.call(root).catch(() => {});
|
||||||
|
} catch (e) { /* юзер запретил — работаем в окне */ }
|
||||||
|
}, []);
|
||||||
|
const exitEditorFullscreen = React.useCallback(() => {
|
||||||
|
try {
|
||||||
|
const ex = document.exitFullscreen || document.webkitExitFullscreen
|
||||||
|
|| document.mozCancelFullScreen || document.msExitFullscreen;
|
||||||
|
if (ex && document.fullscreenElement) ex.call(document).catch?.(() => {});
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
}, []);
|
||||||
|
const toggleEditorFullscreen = React.useCallback(() => {
|
||||||
|
if (document.fullscreenElement) exitEditorFullscreen();
|
||||||
|
else requestEditorFullscreen();
|
||||||
|
}, [requestEditorFullscreen, exitEditorFullscreen]);
|
||||||
|
// Следим за состоянием fullscreen (кнопка показывает актуальную иконку).
|
||||||
|
useEffect(() => {
|
||||||
|
const onFsChange = () => setIsFullscreen(!!document.fullscreenElement);
|
||||||
|
document.addEventListener('fullscreenchange', onFsChange);
|
||||||
|
document.addEventListener('webkitfullscreenchange', onFsChange);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('fullscreenchange', onFsChange);
|
||||||
|
document.removeEventListener('webkitfullscreenchange', onFsChange);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
// Автовход в fullscreen при ПЕРВОМ клике/нажатии по редактору. Один раз.
|
||||||
|
useEffect(() => {
|
||||||
|
// В десктоп-приложении окно и так на весь экран — авто-FS не нужен.
|
||||||
|
if (IS_DESKTOP_APP) return;
|
||||||
|
const tryAuto = () => {
|
||||||
|
if (fsAutoTriedRef.current) return;
|
||||||
|
fsAutoTriedRef.current = true;
|
||||||
|
if (!document.fullscreenElement) requestEditorFullscreen();
|
||||||
|
};
|
||||||
|
window.addEventListener('pointerdown', tryAuto, { once: true, capture: true });
|
||||||
|
window.addEventListener('keydown', tryAuto, { once: true, capture: true });
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('pointerdown', tryAuto, { capture: true });
|
||||||
|
window.removeEventListener('keydown', tryAuto, { capture: true });
|
||||||
|
};
|
||||||
|
}, [requestEditorFullscreen]);
|
||||||
|
// При уходе со страницы редактора — выходим из fullscreen.
|
||||||
|
useEffect(() => () => { exitEditorFullscreen(); }, [exitEditorFullscreen]);
|
||||||
|
|
||||||
|
// === Регулируемая граница между «Объекты сцены» и «Свойства» ===
|
||||||
|
// Доля высоты под список объектов (0.2..0.85). Сохраняем в localStorage.
|
||||||
|
const [hierFraction, setHierFraction] = useState(() => {
|
||||||
|
const v = parseFloat(localStorage.getItem('rbxStudioHierFraction'));
|
||||||
|
return Number.isFinite(v) && v >= 0.2 && v <= 0.85 ? v : 0.5;
|
||||||
|
});
|
||||||
|
const rightPanelRef = useRef(null);
|
||||||
|
const splitDragRef = useRef(false);
|
||||||
|
useEffect(() => {
|
||||||
|
const onMove = (e) => {
|
||||||
|
if (!splitDragRef.current || !rightPanelRef.current) return;
|
||||||
|
const rect = rightPanelRef.current.getBoundingClientRect();
|
||||||
|
// Доля от верха панели до курсора (за вычетом верхнего заголовка ~24px).
|
||||||
|
let f = (e.clientY - rect.top - 24) / Math.max(1, rect.height - 24);
|
||||||
|
f = Math.max(0.2, Math.min(0.85, f));
|
||||||
|
setHierFraction(f);
|
||||||
|
};
|
||||||
|
const onUp = () => {
|
||||||
|
if (!splitDragRef.current) return;
|
||||||
|
splitDragRef.current = false;
|
||||||
|
document.body.style.cursor = '';
|
||||||
|
try { localStorage.setItem('rbxStudioHierFraction', String(hierFraction)); } catch (_) {}
|
||||||
|
};
|
||||||
|
window.addEventListener('pointermove', onMove);
|
||||||
|
window.addEventListener('pointerup', onUp);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('pointermove', onMove);
|
||||||
|
window.removeEventListener('pointerup', onUp);
|
||||||
|
};
|
||||||
|
}, [hierFraction]);
|
||||||
|
const startSplitDrag = React.useCallback((e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
splitDragRef.current = true;
|
||||||
|
document.body.style.cursor = 'row-resize';
|
||||||
|
}, []);
|
||||||
// Team Create — клиент совместного редактирования + presence-overlay.
|
// Team Create — клиент совместного редактирования + presence-overlay.
|
||||||
const collabRef = useRef(null);
|
const collabRef = useRef(null);
|
||||||
const collabOverlayRef = useRef(null);
|
const collabOverlayRef = useRef(null);
|
||||||
@ -2136,7 +2233,9 @@ const KubikonEditor = () => {
|
|||||||
// fullscreen — иначе Ctrl+W/Ctrl+D случайно закрывают вкладку
|
// fullscreen — иначе Ctrl+W/Ctrl+D случайно закрывают вкладку
|
||||||
// в режиме игры. Это user gesture (клик по кнопке Play),
|
// в режиме игры. Это user gesture (клик по кнопке Play),
|
||||||
// поэтому requestFullscreen() разрешён.
|
// поэтому requestFullscreen() разрешён.
|
||||||
try {
|
// В десктоп-приложении этого риска нет (нет вкладок браузера) —
|
||||||
|
// окно и так на весь экран, FS не нужен.
|
||||||
|
if (!IS_DESKTOP_APP) try {
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
const req = root.requestFullscreen
|
const req = root.requestFullscreen
|
||||||
|| root.webkitRequestFullscreen
|
|| root.webkitRequestFullscreen
|
||||||
@ -2299,6 +2398,18 @@ const KubikonEditor = () => {
|
|||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{/* Полноэкранный режим — съедает верхнюю панель браузера.
|
||||||
|
В десктоп-приложении не нужен (окно и так на весь экран). */}
|
||||||
|
{!IS_DESKTOP_APP && (
|
||||||
|
<button
|
||||||
|
onClick={toggleEditorFullscreen}
|
||||||
|
title={isFullscreen ? 'Выйти из полноэкранного режима (F11)' : 'На весь экран (F11)'}
|
||||||
|
className={cl.toolbarBtn}
|
||||||
|
style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 38, height: 38, padding: 0, flexShrink: 0 }}
|
||||||
|
>
|
||||||
|
<Icon name={isFullscreen ? 'fullscreen-exit' : 'fullscreen'} size={16} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
{/* Кнопка баг-репорта в шапке — кликает по скрытой плавающей. */}
|
{/* Кнопка баг-репорта в шапке — кликает по скрытой плавающей. */}
|
||||||
<button
|
<button
|
||||||
onClick={() => document.querySelector('[data-kubikon-bug-btn]')?.click()}
|
onClick={() => document.querySelector('[data-kubikon-bug-btn]')?.click()}
|
||||||
@ -3510,7 +3621,8 @@ const KubikonEditor = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Правая панель — Hierarchy + Inspector */}
|
{/* Правая панель — Hierarchy + Inspector */}
|
||||||
<aside className={cl.rightPanel}>
|
<aside className={cl.rightPanel} ref={rightPanelRef}>
|
||||||
|
<div className={cl.rightSection} style={{ flexGrow: hierFraction, flexBasis: 0 }}>
|
||||||
<div className={cl.panelTitle}>Объекты сцены</div>
|
<div className={cl.panelTitle}>Объекты сцены</div>
|
||||||
<HierarchyPanel
|
<HierarchyPanel
|
||||||
blocks={blocksList}
|
blocks={blocksList}
|
||||||
@ -3735,7 +3847,16 @@ const KubikonEditor = () => {
|
|||||||
onAssignToFolder={(kind, ref, folderId) =>
|
onAssignToFolder={(kind, ref, folderId) =>
|
||||||
sceneRef.current?.assignToFolder(kind, ref, folderId)}
|
sceneRef.current?.assignToFolder(kind, ref, folderId)}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Перетаскиваемая граница между списком объектов и свойствами. */}
|
||||||
|
<div
|
||||||
|
className={cl.rightSplitter}
|
||||||
|
onPointerDown={startSplitDrag}
|
||||||
|
title="Потяните, чтобы изменить высоту"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className={cl.rightSection} style={{ flexGrow: (1 - hierFraction), flexBasis: 0 }}>
|
||||||
<div className={cl.panelTitle}>Свойства</div>
|
<div className={cl.panelTitle}>Свойства</div>
|
||||||
<InspectorPanel
|
<InspectorPanel
|
||||||
selection={selection}
|
selection={selection}
|
||||||
@ -3872,6 +3993,7 @@ const KubikonEditor = () => {
|
|||||||
markDirty();
|
markDirty();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,8 @@
|
|||||||
font-family: "Roboto Condensed", system-ui, -apple-system, sans-serif;
|
font-family: "Roboto Condensed", system-ui, -apple-system, sans-serif;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 56px auto 1fr 28px;
|
/* UI уменьшен на ~10% (ближе к Roblox Studio): topbar 56→50, status 28→26. */
|
||||||
|
grid-template-rows: 50px auto 1fr 26px;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
@ -39,7 +40,7 @@
|
|||||||
color: var(--text);
|
color: var(--text);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
font-size: 14px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor *,
|
.editor *,
|
||||||
@ -52,8 +53,8 @@
|
|||||||
.topBar {
|
.topBar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 16px;
|
gap: 12px;
|
||||||
padding: 0 16px;
|
padding: 0 14px;
|
||||||
background: linear-gradient(180deg, var(--bg-dark) 0%, var(--bg-darkest) 100%);
|
background: linear-gradient(180deg, var(--bg-dark) 0%, var(--bg-darkest) 100%);
|
||||||
border-bottom: 2px solid var(--border);
|
border-bottom: 2px solid var(--border);
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
@ -145,12 +146,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.toolbarBtn {
|
.toolbarBtn {
|
||||||
padding: 8px 16px;
|
padding: 7px 13px;
|
||||||
background: var(--bg-mid);
|
background: var(--bg-mid);
|
||||||
border: 2px solid var(--border);
|
border: 2px solid var(--border);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
font-size: 13px;
|
font-size: 12px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.15s;
|
transition: all 0.15s;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@ -210,7 +211,9 @@
|
|||||||
/* === WORKSPACE === */
|
/* === WORKSPACE === */
|
||||||
.workspace {
|
.workspace {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 240px minmax(0, 1fr) 280px;
|
/* Правая панель шире (280→320) — длинные имена объектов не обрезаются,
|
||||||
|
больше места под список и свойства. Левая чуть уже (240→224). */
|
||||||
|
grid-template-columns: 224px minmax(0, 1fr) 320px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
@ -233,18 +236,61 @@
|
|||||||
|
|
||||||
.rightPanel {
|
.rightPanel {
|
||||||
border-left: 2px solid var(--border);
|
border-left: 2px solid var(--border);
|
||||||
|
overflow: hidden; /* секции скроллятся внутри себя, панель — нет */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Секция правой панели (список объектов / свойства) — занимает свою долю
|
||||||
|
высоты, скроллится независимо. Доля регулируется сплиттером. */
|
||||||
|
.rightSection {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Перетаскиваемая граница между списком объектов и свойствами. */
|
||||||
|
.rightSplitter {
|
||||||
|
height: 6px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
cursor: row-resize;
|
||||||
|
background: var(--bg-mid);
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
position: relative;
|
||||||
|
transition: background 0.12s;
|
||||||
|
}
|
||||||
|
.rightSplitter::before {
|
||||||
|
/* визуальная «ручка» — три точки по центру */
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 28px;
|
||||||
|
height: 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: var(--text-dim);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.rightSplitter:hover {
|
||||||
|
background: var(--accent);
|
||||||
|
}
|
||||||
|
.rightSplitter:hover::before {
|
||||||
|
background: #fff;
|
||||||
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panelTitle {
|
.panelTitle {
|
||||||
padding: 12px 16px;
|
padding: 7px 14px;
|
||||||
font-size: 11px;
|
font-size: 10px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 1.5px;
|
letter-spacing: 1.3px;
|
||||||
color: var(--text-dim);
|
color: var(--text-dim);
|
||||||
background: var(--bg-mid);
|
background: var(--bg-mid);
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
border-top: 1px solid var(--border);
|
border-top: 1px solid var(--border);
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panelTitle:first-child {
|
.panelTitle:first-child {
|
||||||
|
|||||||
@ -789,7 +789,8 @@ const KubikonPlayer = () => {
|
|||||||
|| root.webkitRequestFullscreen
|
|| root.webkitRequestFullscreen
|
||||||
|| root.mozRequestFullScreen
|
|| root.mozRequestFullScreen
|
||||||
|| root.msRequestFullscreen;
|
|| root.msRequestFullscreen;
|
||||||
if (req) {
|
// В десктоп-приложении (Electron) окно и так на весь экран — FS не нужен.
|
||||||
|
if (req && !(typeof window !== 'undefined' && window.__RUBLOX_DESKTOP__)) {
|
||||||
try { await req.call(root); } catch (e) { /* отменено */ }
|
try { await req.call(root); } catch (e) { /* отменено */ }
|
||||||
}
|
}
|
||||||
setMobileStartTapped(true);
|
setMobileStartTapped(true);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user